rcpp_framework/modules/drogon/trantor/utils/Logger.h

384 lines
13 KiB
C++

/**
*
* @file Logger.h
* @author An Tao
*
* Public header file in trantor lib.
*
* Copyright 2018, An Tao. All rights reserved.
* Use of this source code is governed by a BSD-style license
* that can be found in the License file.
*
*
*/
#pragma once
#include <trantor/utils/NonCopyable.h>
#include <trantor/utils/Date.h>
#include <trantor/utils/LogStream.h>
#include <trantor/exports.h>
#include <cstring>
#include <functional>
#include <iostream>
#include <vector>
namespace trantor
{
/**
* @brief This class implements log functions.
*
*/
class TRANTOR_EXPORT Logger : public NonCopyable
{
public:
enum LogLevel
{
kTrace = 0,
kDebug,
kInfo,
kWarn,
kError,
kFatal,
kNumberOfLogLevels
};
/**
* @brief Calculate of basename of source files in compile time.
*
*/
class SourceFile
{
public:
template <int N>
inline SourceFile(const char (&arr)[N]) : data_(arr), size_(N - 1)
{
// std::cout<<data_<<std::endl;
const char *slash = strrchr(data_, '/'); // builtin function
if (slash)
{
data_ = slash + 1;
size_ -= static_cast<int>(data_ - arr);
}
}
explicit SourceFile(const char *filename) : data_(filename)
{
const char *slash = strrchr(filename, '/');
if (slash)
{
data_ = slash + 1;
}
size_ = static_cast<int>(strlen(data_));
}
const char *data_;
int size_;
};
Logger(SourceFile file, int line);
Logger(SourceFile file, int line, LogLevel level);
Logger(SourceFile file, int line, bool isSysErr);
Logger(SourceFile file, int line, LogLevel level, const char *func);
~Logger();
Logger &setIndex(int index)
{
index_ = index;
return *this;
}
LogStream &stream();
/**
* @brief Set the output function.
*
* @param outputFunc The function to output a log message.
* @param flushFunc The function to flush.
* @note Logs are output to the standard output by default.
*/
static void setOutputFunction(
std::function<void(const char *msg, const uint64_t len)> outputFunc,
std::function<void()> flushFunc,
int index = -1)
{
if (index < 0)
{
outputFunc_() = outputFunc;
flushFunc_() = flushFunc;
}
else
{
outputFunc_(index) = outputFunc;
flushFunc_(index) = flushFunc;
}
}
/**
* @brief Set the log level. Logs below the level are not printed.
*
* @param level
*/
static void setLogLevel(LogLevel level)
{
logLevel_() = level;
}
/**
* @brief Get the current log level.
*
* @return LogLevel
*/
static LogLevel logLevel()
{
return logLevel_();
}
protected:
static void defaultOutputFunction(const char *msg, const uint64_t len)
{
fwrite(msg, 1, len, stdout);
}
static void defaultFlushFunction()
{
fflush(stdout);
}
void formatTime();
static LogLevel &logLevel_()
{
#ifdef RELEASE
static LogLevel logLevel = LogLevel::kInfo;
#else
static LogLevel logLevel = LogLevel::kDebug;
#endif
return logLevel;
}
static std::function<void(const char *msg, const uint64_t len)>
&outputFunc_()
{
static std::function<void(const char *msg, const uint64_t len)>
outputFunc = Logger::defaultOutputFunction;
return outputFunc;
}
static std::function<void()> &flushFunc_()
{
static std::function<void()> flushFunc = Logger::defaultFlushFunction;
return flushFunc;
}
static std::function<void(const char *msg, const uint64_t len)>
&outputFunc_(size_t index)
{
static std::vector<
std::function<void(const char *msg, const uint64_t len)>>
outputFuncs;
if (index < outputFuncs.size())
{
return outputFuncs[index];
}
while (index >= outputFuncs.size())
{
outputFuncs.emplace_back(outputFunc_());
}
return outputFuncs[index];
}
static std::function<void()> &flushFunc_(size_t index)
{
static std::vector<std::function<void()>> flushFuncs;
if (index < flushFuncs.size())
{
return flushFuncs[index];
}
while (index >= flushFuncs.size())
{
flushFuncs.emplace_back(flushFunc_());
}
return flushFuncs[index];
}
friend class RawLogger;
LogStream logStream_;
Date date_{Date::now()};
SourceFile sourceFile_;
int fileLine_;
LogLevel level_;
int index_{-1};
};
class TRANTOR_EXPORT RawLogger : public NonCopyable
{
public:
~RawLogger();
RawLogger &setIndex(int index)
{
index_ = index;
return *this;
}
LogStream &stream()
{
return logStream_;
}
private:
LogStream logStream_;
int index_{-1};
};
#ifdef NDEBUG
#define LOG_TRACE \
if (0) \
trantor::Logger(__FILE__, __LINE__, trantor::Logger::kTrace, __func__) \
.stream()
#else
#define LOG_TRACE \
if (trantor::Logger::logLevel() <= trantor::Logger::kTrace) \
trantor::Logger(__FILE__, __LINE__, trantor::Logger::kTrace, __func__) \
.stream()
#define LOG_TRACE_TO(index) \
if (trantor::Logger::logLevel() <= trantor::Logger::kTrace) \
trantor::Logger(__FILE__, __LINE__, trantor::Logger::kTrace, __func__) \
.setIndex(index) \
.stream()
#endif
#define LOG_DEBUG \
if (trantor::Logger::logLevel() <= trantor::Logger::kDebug) \
trantor::Logger(__FILE__, __LINE__, trantor::Logger::kDebug, __func__) \
.stream()
#define LOG_DEBUG_TO(index) \
if (trantor::Logger::logLevel() <= trantor::Logger::kDebug) \
trantor::Logger(__FILE__, __LINE__, trantor::Logger::kDebug, __func__) \
.setIndex(index) \
.stream()
#define LOG_INFO \
if (trantor::Logger::logLevel() <= trantor::Logger::kInfo) \
trantor::Logger(__FILE__, __LINE__).stream()
#define LOG_INFO_TO(index) \
if (trantor::Logger::logLevel() <= trantor::Logger::kInfo) \
trantor::Logger(__FILE__, __LINE__).setIndex(index).stream()
#define LOG_WARN \
trantor::Logger(__FILE__, __LINE__, trantor::Logger::kWarn).stream()
#define LOG_WARN_TO(index) \
trantor::Logger(__FILE__, __LINE__, trantor::Logger::kWarn) \
.setIndex(index) \
.stream()
#define LOG_ERROR \
trantor::Logger(__FILE__, __LINE__, trantor::Logger::kError).stream()
#define LOG_ERROR_TO(index) \
trantor::Logger(__FILE__, __LINE__, trantor::Logger::kError) \
.setIndex(index) \
.stream()
#define LOG_FATAL \
trantor::Logger(__FILE__, __LINE__, trantor::Logger::kFatal).stream()
#define LOG_FATAL_TO(index) \
trantor::Logger(__FILE__, __LINE__, trantor::Logger::kFatal) \
.setIndex(index) \
.stream()
#define LOG_SYSERR trantor::Logger(__FILE__, __LINE__, true).stream()
#define LOG_SYSERR_TO(index) \
trantor::Logger(__FILE__, __LINE__, true).setIndex(index).stream()
#define LOG_RAW trantor::RawLogger().stream()
#define LOG_RAW_TO(index) trantor::RawLogger().setIndex(index).stream()
#define LOG_TRACE_IF(cond) \
if ((trantor::Logger::logLevel() <= trantor::Logger::kTrace) && (cond)) \
trantor::Logger(__FILE__, __LINE__, trantor::Logger::kTrace, __func__) \
.stream()
#define LOG_DEBUG_IF(cond) \
if ((Tensor::Logger::logLevel() <= Tensor::Logger::kDebug) && (cond)) \
Tensor::Logger(__FILE__, __LINE__, Tensor::Logger::kDebug, __func__) \
.stream()
#define LOG_INFO_IF(cond) \
if ((Tensor::Logger::logLevel() <= Tensor::Logger::kInfo) && (cond)) \
Tensor::Logger(__FILE__, __LINE__).stream()
#define LOG_WARN_IF(cond) \
if (cond) \
Tensor::Logger(__FILE__, __LINE__, Tensor::Logger::kWarn).stream()
#define LOG_ERROR_IF(cond) \
if (cond) \
Tensor::Logger(__FILE__, __LINE__, Tensor::Logger::kError).stream()
#define LOG_FATAL_IF(cond) \
if (cond) \
Tensor::Logger(__FILE__, __LINE__, Tensor::Logger::kFatal).stream()
#ifdef NDEBUG
#define DLOG_TRACE \
if (0) \
trantor::Logger(__FILE__, __LINE__, trantor::Logger::kTrace, __func__) \
.stream()
#define DLOG_DEBUG \
if (0) \
Tensor::Logger(__FILE__, __LINE__, Tensor::Logger::kDebug, __func__) \
.stream()
#define DLOG_INFO \
if (0) \
Tensor::Logger(__FILE__, __LINE__).stream()
#define DLOG_WARN \
if (0) \
Tensor::Logger(__FILE__, __LINE__, Tensor::Logger::kWarn).stream()
#define DLOG_ERROR \
if (0) \
Tensor::Logger(__FILE__, __LINE__, Tensor::Logger::kError).stream()
#define DLOG_FATAL \
if (0) \
Tensor::Logger(__FILE__, __LINE__, Tensor::Logger::kFatal).stream()
#define DLOG_TRACE_IF(cond) \
if (0) \
trantor::Logger(__FILE__, __LINE__, trantor::Logger::kTrace, __func__) \
.stream()
#define DLOG_DEBUG_IF(cond) \
if (0) \
Tensor::Logger(__FILE__, __LINE__, Tensor::Logger::kDebug, __func__) \
.stream()
#define DLOG_INFO_IF(cond) \
if (0) \
Tensor::Logger(__FILE__, __LINE__).stream()
#define DLOG_WARN_IF(cond) \
if (0) \
Tensor::Logger(__FILE__, __LINE__, Tensor::Logger::kWarn).stream()
#define DLOG_ERROR_IF(cond) \
if (0) \
Tensor::Logger(__FILE__, __LINE__, Tensor::Logger::kError).stream()
#define DLOG_FATAL_IF(cond) \
if (0) \
Tensor::Logger(__FILE__, __LINE__, Tensor::Logger::kFatal).stream()
#else
#define DLOG_TRACE \
if (trantor::Logger::logLevel() <= trantor::Logger::kTrace) \
trantor::Logger(__FILE__, __LINE__, trantor::Logger::kTrace, __func__) \
.stream()
#define DLOG_DEBUG \
if (Tensor::Logger::logLevel() <= Tensor::Logger::kDebug) \
Tensor::Logger(__FILE__, __LINE__, Tensor::Logger::kDebug, __func__) \
.stream()
#define DLOG_INFO \
if (Tensor::Logger::logLevel() <= Tensor::Logger::kInfo) \
Tensor::Logger(__FILE__, __LINE__).stream()
#define DLOG_WARN \
Tensor::Logger(__FILE__, __LINE__, Tensor::Logger::kWarn).stream()
#define DLOG_ERROR \
Tensor::Logger(__FILE__, __LINE__, Tensor::Logger::kError).stream()
#define DLOG_FATAL \
Tensor::Logger(__FILE__, __LINE__, Tensor::Logger::kFatal).stream()
#define DLOG_TRACE_IF(cond) \
if ((trantor::Logger::logLevel() <= trantor::Logger::kTrace) && (cond)) \
trantor::Logger(__FILE__, __LINE__, trantor::Logger::kTrace, __func__) \
.stream()
#define DLOG_DEBUG_IF(cond) \
if ((Tensor::Logger::logLevel() <= Tensor::Logger::kDebug) && (cond)) \
Tensor::Logger(__FILE__, __LINE__, Tensor::Logger::kDebug, __func__) \
.stream()
#define DLOG_INFO_IF(cond) \
if ((Tensor::Logger::logLevel() <= Tensor::Logger::kInfo) && (cond)) \
Tensor::Logger(__FILE__, __LINE__).stream()
#define DLOG_WARN_IF(cond) \
if (cond) \
Tensor::Logger(__FILE__, __LINE__, Tensor::Logger::kWarn).stream()
#define DLOG_ERROR_IF(cond) \
if (cond) \
Tensor::Logger(__FILE__, __LINE__, Tensor::Logger::kError).stream()
#define DLOG_FATAL_IF(cond) \
if (cond) \
Tensor::Logger(__FILE__, __LINE__, Tensor::Logger::kFatal).stream()
#endif
const char *strerror_tl(int savedErrno);
} // namespace trantor