#include "logger.h" #include #include #include #include #include #include #include #include namespace NYT { //////////////////////////////////////////////////////////////////////////////// static TStringBuf StripFileName(TStringBuf path) { TStringBuf l, r; if (path.TryRSplit('/', l, r) || path.TryRSplit('\\', l, r)) { return r; } else { return path; } } static char GetLogLevelCode(ILogger::ELevel level) { switch (level) { case ILogger::FATAL: return 'F'; case ILogger::ERROR: return 'E'; case ILogger::INFO: return 'I'; case ILogger::DEBUG: return 'D'; } Y_UNREACHABLE(); } //////////////////////////////////////////////////////////////////////////////// class TNullLogger : public ILogger { public: void Log(ELevel level, const TSourceLocation& sourceLocation, const char* format, va_list args) override { Y_UNUSED(level); Y_UNUSED(sourceLocation); Y_UNUSED(format); Y_UNUSED(args); } }; //////////////////////////////////////////////////////////////////////////////// class TLoggerBase : public ILogger { public: TLoggerBase(ELevel cutLevel) : CutLevel_(cutLevel) { } virtual void OutputLine(const TString& line) = 0; void Log(ELevel level, const TSourceLocation& sourceLocation, const char* format, va_list args) override { if (level > CutLevel_) { return; } TStringStream stream; stream << TInstant::Now().ToStringLocal() << " " << GetLogLevelCode(level) << " [" << Hex(TThread::CurrentThreadId(), HF_FULL) << "] "; Printf(stream, format, args); stream << " - " << StripFileName(sourceLocation.File) << ':' << sourceLocation.Line << Endl; TGuard guard(Mutex_); OutputLine(stream.Str()); } private: ELevel CutLevel_; TMutex Mutex_; }; //////////////////////////////////////////////////////////////////////////////// class TStdErrLogger : public TLoggerBase { public: TStdErrLogger(ELevel cutLevel) : TLoggerBase(cutLevel) { } void OutputLine(const TString& line) override { Cerr << line; } }; ILoggerPtr CreateStdErrLogger(ILogger::ELevel cutLevel) { return new TStdErrLogger(cutLevel); } //////////////////////////////////////////////////////////////////////////////// class TFileLogger : public TLoggerBase { public: TFileLogger(ELevel cutLevel, const TString& path, bool append) : TLoggerBase(cutLevel) , Stream_(TFile(path, OpenAlways | WrOnly | Seq | (append ? ForAppend : EOpenMode()))) { } void OutputLine(const TString& line) override { Stream_ << line; } private: TUnbufferedFileOutput Stream_; }; ILoggerPtr CreateFileLogger(ILogger::ELevel cutLevel, const TString& path, bool append) { return new TFileLogger(cutLevel, path, append); } //////////////////////////////////////////////////////////////////////////////// class TBufferedFileLogger : public TLoggerBase { public: TBufferedFileLogger(ELevel cutLevel, const TString& path, bool append) : TLoggerBase(cutLevel) , Stream_(TFile(path, OpenAlways | WrOnly | Seq | (append ? ForAppend : EOpenMode()))) { } void OutputLine(const TString& line) override { Stream_ << line; } private: TFileOutput Stream_; }; ILoggerPtr CreateBufferedFileLogger(ILogger::ELevel cutLevel, const TString& path, bool append) { return new TBufferedFileLogger(cutLevel, path, append); } //////////////////////////////////////////////////////////////////////////////// static TRWMutex LoggerMutex; static ILoggerPtr Logger; struct TLoggerInitializer { TLoggerInitializer() { Logger = new TNullLogger; } } LoggerInitializer; void SetLogger(ILoggerPtr logger) { auto guard = TWriteGuard(LoggerMutex); if (logger) { Logger = logger; } else { Logger = new TNullLogger; } } ILoggerPtr GetLogger() { auto guard = TReadGuard(LoggerMutex); return Logger; } //////////////////////////////////////////////////////////////////////////////// }