aboutsummaryrefslogblamecommitdiffstats
path: root/yt/cpp/mapreduce/interface/logging/logger.cpp
blob: bfa56b94f6d57c2cb3419ac2d696625ed6772072 (plain) (tree)


























































































































































































                                                                                                            
#include "logger.h"

#include <util/datetime/base.h>

#include <util/stream/file.h>
#include <util/stream/format.h>
#include <util/stream/printf.h>
#include <util/stream/str.h>

#include <util/system/mutex.h>
#include <util/system/rwlock.h>
#include <util/system/thread.h>

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<TMutex> 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;
}

////////////////////////////////////////////////////////////////////////////////

}