log.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428
  1. #include "log.h"
  2. #include <yql/essentials/utils/log/proto/logger_config.pb.h>
  3. #include <yql/essentials/utils/backtrace/backtrace.h>
  4. #include <library/cpp/logger/stream.h>
  5. #include <library/cpp/logger/system.h>
  6. #include <library/cpp/logger/composite.h>
  7. #include <util/datetime/systime.h>
  8. #include <util/generic/strbuf.h>
  9. #include <util/stream/format.h>
  10. #include <util/system/getpid.h>
  11. #include <util/system/mutex.h>
  12. #include <util/system/progname.h>
  13. #include <util/system/thread.i>
  14. #include <stdio.h>
  15. #include <time.h>
  16. static TMutex g_InitLoggerMutex;
  17. static int g_LoggerInitialized = 0;
  18. namespace {
  19. class TLimitedLogBackend final : public TLogBackend {
  20. public:
  21. TLimitedLogBackend(TAutoPtr<TLogBackend> b, TAtomic& flag, ui64 limit) noexcept
  22. : Backend(b)
  23. , Flag(flag)
  24. , Limit(limit)
  25. {
  26. }
  27. ~TLimitedLogBackend() final {
  28. }
  29. void ReopenLog() final {
  30. Backend->ReopenLog();
  31. }
  32. void WriteData(const TLogRecord& rec) final {
  33. const auto remaining = AtomicGet(Limit);
  34. const bool final = remaining > 0 && AtomicSub(Limit, rec.Len) <= 0;
  35. if (remaining > 0 || rec.Priority <= TLOG_WARNING) {
  36. Backend->WriteData(rec);
  37. }
  38. if (final) {
  39. AtomicSet(Flag, 1);
  40. }
  41. }
  42. private:
  43. THolder<TLogBackend> Backend;
  44. TAtomic& Flag;
  45. TAtomic Limit;
  46. };
  47. class TEmergencyLogOutput: public IOutputStream {
  48. public:
  49. TEmergencyLogOutput()
  50. : Current_(Buf_)
  51. , End_(Y_ARRAY_END(Buf_))
  52. {
  53. }
  54. ~TEmergencyLogOutput() {
  55. }
  56. private:
  57. inline size_t Avail() const noexcept {
  58. return End_ - Current_;
  59. }
  60. void DoFlush() override {
  61. if (Current_ != Buf_) {
  62. NYql::NLog::YqlLogger().Write(TLOG_EMERG, Buf_, Current_ - Buf_);
  63. Current_ = Buf_;
  64. }
  65. }
  66. void DoWrite(const void* buf, size_t len) override {
  67. len = Min(len, Avail());
  68. if (len) {
  69. char* end = Current_ + len;
  70. memcpy(Current_, buf, len);
  71. Current_ = end;
  72. }
  73. }
  74. private:
  75. char Buf_[1 << 20];
  76. char* Current_;
  77. char* const End_;
  78. };
  79. TEmergencyLogOutput EMERGENCY_LOG_OUT;
  80. void LogBacktraceOnSignal(int signum) {
  81. if (NYql::NLog::IsYqlLoggerInitialized()) {
  82. EMERGENCY_LOG_OUT <<
  83. #ifdef _win_
  84. signum
  85. #else
  86. strsignal(signum)
  87. #endif
  88. << TStringBuf(" (pid=") << GetPID() << TStringBuf("): ");
  89. NYql::NBacktrace::KikimrBackTraceFormatImpl(&EMERGENCY_LOG_OUT);
  90. EMERGENCY_LOG_OUT.Flush();
  91. }
  92. }
  93. // Conversions between NYql::NProto::TLoggingConfig enums and NYql::NLog enums
  94. NYql::NLog::ELevel ConvertLevel(NYql::NProto::TLoggingConfig::ELevel level) {
  95. using namespace NYql::NProto;
  96. using namespace NYql::NLog;
  97. switch (level) {
  98. case TLoggingConfig::FATAL: return ELevel::FATAL;
  99. case TLoggingConfig::ERROR: return ELevel::ERROR;
  100. case TLoggingConfig::WARN: return ELevel::WARN;
  101. case TLoggingConfig::INFO: return ELevel::INFO;
  102. case TLoggingConfig::DEBUG: return ELevel::DEBUG;
  103. case TLoggingConfig::TRACE: return ELevel::TRACE;
  104. }
  105. ythrow yexception() << "unknown log level: "
  106. << TLoggingConfig::ELevel_Name(level);
  107. }
  108. NYql::NLog::EComponent ConvertComponent(NYql::NProto::TLoggingConfig::EComponent c) {
  109. using namespace NYql::NProto;
  110. using namespace NYql::NLog;
  111. switch (c) {
  112. case TLoggingConfig::DEFAULT: return EComponent::Default;
  113. case TLoggingConfig::CORE: return EComponent::Core;
  114. case TLoggingConfig::CORE_EVAL: return EComponent::CoreEval;
  115. case TLoggingConfig::CORE_PEEPHOLE: return EComponent::CorePeepHole;
  116. case TLoggingConfig::CORE_EXECUTION: return EComponent::CoreExecution;
  117. case TLoggingConfig::SQL: return EComponent::Sql;
  118. case TLoggingConfig::PROVIDER_COMMON: return EComponent::ProviderCommon;
  119. case TLoggingConfig::PROVIDER_CONFIG: return EComponent::ProviderConfig;
  120. case TLoggingConfig::PROVIDER_RESULT: return EComponent::ProviderResult;
  121. case TLoggingConfig::PROVIDER_YT: return EComponent::ProviderYt;
  122. case TLoggingConfig::PROVIDER_KIKIMR: return EComponent::ProviderKikimr;
  123. case TLoggingConfig::PROVIDER_KQP: return EComponent::ProviderKqp;
  124. case TLoggingConfig::PROVIDER_RTMR: return EComponent::ProviderRtmr;
  125. case TLoggingConfig::PERFORMANCE: return EComponent::Perf;
  126. case TLoggingConfig::NET: return EComponent::Net;
  127. case TLoggingConfig::PROVIDER_STAT: return EComponent::ProviderStat;
  128. case TLoggingConfig::PROVIDER_SOLOMON: return EComponent::ProviderSolomon;
  129. case TLoggingConfig::PROVIDER_DQ: return EComponent::ProviderDq;
  130. case TLoggingConfig::PROVIDER_CLICKHOUSE: return EComponent::ProviderClickHouse;
  131. case TLoggingConfig::PROVIDER_YDB: return EComponent::ProviderYdb;
  132. case TLoggingConfig::PROVIDER_PQ: return EComponent::ProviderPq;
  133. case TLoggingConfig::PROVIDER_S3: return EComponent::ProviderS3;
  134. case TLoggingConfig::CORE_DQ: return EComponent::CoreDq;
  135. case TLoggingConfig::HTTP_GATEWAY: return EComponent::HttpGateway;
  136. case TLoggingConfig::PROVIDER_GENERIC: return EComponent::ProviderGeneric;
  137. case TLoggingConfig::PROVIDER_PG: return EComponent::ProviderPg;
  138. }
  139. ythrow yexception() << "unknown log component: "
  140. << TLoggingConfig::EComponent_Name(c);
  141. }
  142. TString ConvertDestinationType(NYql::NProto::TLoggingConfig::ELogTo c) {
  143. switch (c) {
  144. case NYql::NProto::TLoggingConfig::STDOUT: return "cout";
  145. case NYql::NProto::TLoggingConfig::STDERR: return "cerr";
  146. case NYql::NProto::TLoggingConfig::CONSOLE: return "console";
  147. default : {
  148. ythrow yexception() << "unsupported ELogTo destination in Convert";
  149. }
  150. }
  151. ythrow yexception() << "unknown ELogTo destination";
  152. }
  153. NYql::NProto::TLoggingConfig::TLogDestination CreateLogDestination(const TString& c) {
  154. NYql::NProto::TLoggingConfig::TLogDestination destination;
  155. if (c == "cout") {
  156. destination.SetType(NYql::NProto::TLoggingConfig::STDOUT);
  157. } else if (c == "cerr") {
  158. destination.SetType(NYql::NProto::TLoggingConfig::STDERR);
  159. } else if (c == "console") {
  160. destination.SetType(NYql::NProto::TLoggingConfig::CONSOLE);
  161. } else {
  162. destination.SetType(NYql::NProto::TLoggingConfig::FILE);
  163. destination.SetTarget(c);
  164. }
  165. return destination;
  166. }
  167. } // namspace
  168. namespace NYql {
  169. namespace NLog {
  170. void WriteLocalTime(IOutputStream* out) {
  171. struct timeval now;
  172. gettimeofday(&now, nullptr);
  173. struct tm tm;
  174. time_t seconds = static_cast<time_t>(now.tv_sec);
  175. localtime_r(&seconds, &tm);
  176. char buf[sizeof("2016-01-02 03:04:05.006")];
  177. int n = strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S.", &tm);
  178. snprintf(buf + n, sizeof(buf) - n, "%03" PRIu32, static_cast<ui32>(now.tv_usec) / 1000);
  179. out->Write(buf, sizeof(buf) - 1);
  180. }
  181. /**
  182. * TYqlLogElement
  183. * automaticaly adds new line char
  184. */
  185. class TYqlLogElement: public TLogElement {
  186. public:
  187. TYqlLogElement(const TLog* parent, ELevel level)
  188. : TLogElement(parent, ELevelHelpers::ToLogPriority(level))
  189. {
  190. }
  191. ~TYqlLogElement() {
  192. *this << '\n';
  193. }
  194. };
  195. TYqlLog::TYqlLog()
  196. : TLog()
  197. , ProcName_()
  198. , ProcId_()
  199. , WriteTruncMsg_(0) {}
  200. TYqlLog::TYqlLog(const TString& logType, const TComponentLevels& levels)
  201. : TLog(logType)
  202. , ProcName_(GetProgramName())
  203. , ProcId_(GetPID())
  204. , WriteTruncMsg_(0)
  205. {
  206. for (size_t component = 0; component < levels.size(); ++component) {
  207. SetComponentLevel(EComponentHelpers::FromInt(component), levels[component]);
  208. }
  209. }
  210. TYqlLog::TYqlLog(TAutoPtr<TLogBackend> backend, const TComponentLevels& levels)
  211. : TLog(backend)
  212. , ProcName_(GetProgramName())
  213. , ProcId_(GetPID())
  214. , WriteTruncMsg_(0)
  215. {
  216. for (size_t component = 0; component < levels.size(); ++component) {
  217. SetComponentLevel(EComponentHelpers::FromInt(component), levels[component]);
  218. }
  219. }
  220. void TYqlLog::UpdateProcInfo(const TString& procName) {
  221. ProcName_ = procName;
  222. ProcId_ = GetPID();
  223. }
  224. TAutoPtr<TLogElement> TYqlLog::CreateLogElement(
  225. EComponent component, ELevel level,
  226. TStringBuf file, int line) const
  227. {
  228. const bool writeMsg = AtomicCas(&WriteTruncMsg_, 0, 1);
  229. auto element = MakeHolder<TYqlLogElement>(this, writeMsg ? ELevel::FATAL : level);
  230. if (writeMsg) {
  231. WriteLogPrefix(element.Get(), EComponent::Default, ELevel::FATAL, __FILE__, __LINE__);
  232. *element << "Log is truncated by limit\n";
  233. *element << ELevelHelpers::ToLogPriority(level);
  234. }
  235. WriteLogPrefix(element.Get(), component, level, file, line);
  236. return element.Release();
  237. }
  238. void TYqlLog::WriteLogPrefix(IOutputStream* out, EComponent component, ELevel level, TStringBuf file, int line) const {
  239. // LOG FORMAT:
  240. // {datetime} {level} {procname}(pid={pid}, tid={tid}) [{component}] {source_location}: {message}\n
  241. //
  242. WriteLocalTime(out);
  243. *out << ' '
  244. << ELevelHelpers::ToString(level) << ' '
  245. << ProcName_ << TStringBuf("(pid=") << ProcId_
  246. << TStringBuf(", tid=")
  247. #ifdef _unix_
  248. << Hex(SystemCurrentThreadIdImpl())
  249. #else
  250. << SystemCurrentThreadIdImpl()
  251. #endif
  252. << TStringBuf(") [") << EComponentHelpers::ToString(component)
  253. << TStringBuf("] ")
  254. << file.RAfter(LOCSLASH_C) << ':' << line << TStringBuf(": ");
  255. }
  256. void TYqlLog::SetMaxLogLimit(ui64 limit) {
  257. auto backend = TLog::ReleaseBackend();
  258. TLog::ResetBackend(THolder(new TLimitedLogBackend(backend, WriteTruncMsg_, limit)));
  259. }
  260. void InitLogger(const TString& logType, bool startAsDaemon) {
  261. NProto::TLoggingConfig config;
  262. *config.AddLogDest() = CreateLogDestination(logType);
  263. InitLogger(config, startAsDaemon);
  264. }
  265. void InitLogger(const NProto::TLoggingConfig& config, bool startAsDaemon) {
  266. with_lock(g_InitLoggerMutex) {
  267. ++g_LoggerInitialized;
  268. if (g_LoggerInitialized > 1) {
  269. return;
  270. }
  271. TComponentLevels levels;
  272. if (config.HasAllComponentsLevel()) {
  273. levels.fill(ConvertLevel(config.GetAllComponentsLevel()));
  274. } else {
  275. levels.fill(ELevel::INFO);
  276. }
  277. for (const auto& cmpLevel: config.GetLevels()) {
  278. auto component = ConvertComponent(cmpLevel.GetC());
  279. auto level = ConvertLevel(cmpLevel.GetL());
  280. levels[EComponentHelpers::ToInt(component)] = level;
  281. }
  282. TLoggerOperator<TYqlLog>::Set(new TYqlLog("null", levels));
  283. std::vector<THolder<TLogBackend>> backends;
  284. // Set stderr log destination if none was described in config
  285. if (config.LogDestSize() == 0) {
  286. backends.emplace_back(CreateLogBackend("cerr", LOG_MAX_PRIORITY, false));
  287. }
  288. for (const auto& logDest : config.GetLogDest()) {
  289. // Generate the backend we need and temporary store it
  290. switch (logDest.GetType()) {
  291. case NProto::TLoggingConfig::STDERR:
  292. case NProto::TLoggingConfig::STDOUT:
  293. case NProto::TLoggingConfig::CONSOLE: {
  294. if (!startAsDaemon) {
  295. backends.emplace_back(CreateLogBackend(ConvertDestinationType(logDest.GetType()), LOG_MAX_PRIORITY, false));
  296. }
  297. break;
  298. }
  299. case NProto::TLoggingConfig::FILE: {
  300. backends.emplace_back(CreateLogBackend(logDest.GetTarget(), LOG_MAX_PRIORITY, false));
  301. break;
  302. }
  303. case NProto::TLoggingConfig::SYSLOG: {
  304. backends.emplace_back(MakeHolder<TSysLogBackend>(GetProgramName().data(), TSysLogBackend::TSYSLOG_LOCAL1));
  305. break;
  306. }
  307. default: {
  308. break;
  309. }
  310. }
  311. }
  312. // Combine created backends and set them for logger
  313. auto& logger = TLoggerOperator<TYqlLog>::Log();
  314. if (backends.size() == 1) {
  315. logger.ResetBackend(std::move(backends[0]));
  316. } else if (backends.size() > 1) {
  317. THolder<TCompositeLogBackend> compositeBackend = MakeHolder<TCompositeLogBackend>();
  318. for (auto& backend : backends) {
  319. compositeBackend->AddLogBackend(std::move(backend));
  320. }
  321. logger.ResetBackend(std::move(compositeBackend));
  322. }
  323. }
  324. NYql::NBacktrace::AddAfterFatalCallback([](int signo){ LogBacktraceOnSignal(signo); });
  325. }
  326. void InitLogger(TAutoPtr<TLogBackend> backend) {
  327. with_lock(g_InitLoggerMutex) {
  328. ++g_LoggerInitialized;
  329. if (g_LoggerInitialized > 1) {
  330. return;
  331. }
  332. TComponentLevels levels;
  333. levels.fill(ELevel::INFO);
  334. TLoggerOperator<TYqlLog>::Set(new TYqlLog(backend, levels));
  335. }
  336. NYql::NBacktrace::AddAfterFatalCallback([](int signo){ LogBacktraceOnSignal(signo); });
  337. }
  338. void InitLogger(IOutputStream* out) {
  339. InitLogger(new TStreamLogBackend(out));
  340. }
  341. void CleanupLogger() {
  342. with_lock(g_InitLoggerMutex) {
  343. --g_LoggerInitialized;
  344. if (g_LoggerInitialized > 0) {
  345. return;
  346. }
  347. TLoggerOperator<TYqlLog>::Set(new TYqlLog());
  348. }
  349. }
  350. void ReopenLog() {
  351. with_lock(g_InitLoggerMutex) {
  352. TLoggerOperator<TYqlLog>::Log().ReopenLog();
  353. }
  354. }
  355. } // namespace NLog
  356. } // namespace NYql
  357. /**
  358. * creates default YQL logger writing to /dev/null
  359. */
  360. template <>
  361. NYql::NLog::TYqlLog* CreateDefaultLogger<NYql::NLog::TYqlLog>() {
  362. NYql::NLog::TComponentLevels levels;
  363. levels.fill(NYql::NLog::ELevel::INFO);
  364. return new NYql::NLog::TYqlLog("null", levels);
  365. }