rcpp_framework/core/log/logger.h

398 lines
13 KiB
C++

#ifndef LOGGER_H
#define LOGGER_H
#include "core/math/date.h"
#include "log_stream.h"
#include <cstring>
#include <functional>
#include <iostream>
#include <vector>
class String;
class RLogger {
public:
static void log_trace(const String &str);
static void log_trace(const char *str);
static void log_message(const String &str);
static void log_message(const char *str);
static void log_warning(const String &str);
static void log_warning(const char *str);
static void log_error(const String &str);
static void log_error(const char *str);
static void _log_error(const char *p_function, const char *p_file, int p_line, const char *str);
static void _log_error(const char *p_function, const char *p_file, int p_line, const String &str);
static void _log_msg_error(const char *p_function, const char *p_file, int p_line, const char *p_msg, const char *str);
static void _log_index_error(const char *p_function, const char *p_file, int p_line, const int index, const int size, const char *str);
};
/**
*
* @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.
*
*
*/
namespace trantor {
/**
* @brief This class implements log functions.
*
*/
class Logger {
protected:
Logger(const Logger &) = delete;
Logger &operator=(const Logger &) = delete;
// some uncopyable classes maybe support move constructor....
Logger(Logger &&) noexcept(true) = default;
Logger &operator=(Logger &&) noexcept(true) = default;
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 RawLogger {
protected:
RawLogger(const RawLogger &) = delete;
RawLogger &operator=(const RawLogger &) = delete;
// some uncopyable classes maybe support move constructor....
RawLogger(RawLogger &&) noexcept(true) = default;
RawLogger &operator=(RawLogger &&) noexcept(true) = default;
public:
RawLogger() {}
~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
#endif