blob: 0474a2abc6d017f9209b0f4fc5a9412beaf06bef [file] [log] [blame]
/**
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef LIBMINIFI_INCLUDE_CORE_LOGGING_LOGGER_H_
#define LIBMINIFI_INCLUDE_CORE_LOGGING_LOGGER_H_
#include <string>
#include <mutex>
#include <memory>
#include <sstream>
#include <utility>
#include <iostream>
#include "spdlog/common.h"
#include "spdlog/logger.h"
#include "utils/SmallString.h"
namespace org {
namespace apache {
namespace nifi {
namespace minifi {
namespace core {
namespace logging {
#define LOG_BUFFER_SIZE 1024
class LoggerControl {
public:
LoggerControl();
bool is_enabled() const;
void setEnabled(bool status);
protected:
std::atomic<bool> is_enabled_;
};
inline char const* conditional_conversion(std::string const& str) {
return str.c_str();
}
template<size_t N>
inline char const* conditional_conversion(const utils::SmallString<N>& arr) {
return arr.c_str();
}
template<typename T, typename = typename std::enable_if<
std::is_arithmetic<T>::value ||
std::is_enum<T>::value ||
std::is_pointer<T>::value>::type>
inline T conditional_conversion(T t) {
return t;
}
template<typename ... Args>
inline std::string format_string(char const* format_str, Args&&... args) {
char buf[LOG_BUFFER_SIZE];
std::snprintf(buf, LOG_BUFFER_SIZE, format_str, conditional_conversion(std::forward<Args>(args))...);
return std::string(buf);
}
inline std::string format_string(char const* format_str) {
return format_str;
}
typedef enum {
trace = 0,
debug = 1,
info = 2,
warn = 3,
err = 4,
critical = 5,
off = 6
} LOG_LEVEL;
class BaseLogger {
public:
virtual ~BaseLogger();
virtual void log_string(LOG_LEVEL level, std::string str) = 0;
virtual bool should_log(const LOG_LEVEL &level);
};
/**
* LogBuilder is a class to facilitate using the LOG macros below and an associated put-to operator.
*
*/
class LogBuilder {
public:
LogBuilder(BaseLogger *l, LOG_LEVEL level);
~LogBuilder();
void setIgnore();
void log_string(LOG_LEVEL level);
template<typename T>
LogBuilder &operator<<(const T &o) {
if (!ignore)
str << o;
return *this;
}
bool ignore;
BaseLogger *ptr;
std::stringstream str;
LOG_LEVEL level;
};
class Logger : public BaseLogger {
public:
/**
* @brief Log error message
* @param format format string ('man printf' for syntax)
* @warning does not check @p log or @p format for null. Caller must ensure parameters and format string lengths match
*/
template<typename ... Args>
void log_error(const char * const format, const Args& ... args) {
log(spdlog::level::err, format, args...);
}
/**
* @brief Log warn message
* @param format format string ('man printf' for syntax)
* @warning does not check @p log or @p format for null. Caller must ensure parameters and format string lengths match
*/
template<typename ... Args>
void log_warn(const char * const format, const Args& ... args) {
log(spdlog::level::warn, format, args...);
}
/**
* @brief Log info message
* @param format format string ('man printf' for syntax)
* @warning does not check @p log or @p format for null. Caller must ensure parameters and format string lengths match
*/
template<typename ... Args>
void log_info(const char * const format, const Args& ... args) {
log(spdlog::level::info, format, args...);
}
/**
* @brief Log debug message
* @param format format string ('man printf' for syntax)
* @warning does not check @p log or @p format for null. Caller must ensure parameters and format string lengths match
*/
template<typename ... Args>
void log_debug(const char * const format, const Args& ... args) {
log(spdlog::level::debug, format, args...);
}
/**
* @brief Log trace message
* @param format format string ('man printf' for syntax)
* @warning does not check @p log or @p format for null. Caller must ensure parameters and format string lengths match
*/
template<typename ... Args>
void log_trace(const char * const format, const Args& ... args) {
log(spdlog::level::trace, format, args...);
}
bool should_log(const LOG_LEVEL &level);
virtual void log_string(LOG_LEVEL level, std::string str);
protected:
Logger(std::shared_ptr<spdlog::logger> delegate, std::shared_ptr<LoggerControl> controller);
Logger(std::shared_ptr<spdlog::logger> delegate); // NOLINT
std::shared_ptr<spdlog::logger> delegate_;
std::shared_ptr<LoggerControl> controller_;
std::mutex mutex_;
private:
template<typename ... Args>
inline void log(spdlog::level::level_enum level, const char * const format, const Args& ... args) {
if (controller_ && !controller_->is_enabled())
return;
std::lock_guard<std::mutex> lock(mutex_);
if (!delegate_->should_log(level)) {
return;
}
const auto str = format_string(format, conditional_conversion(args)...);
delegate_->log(level, str);
}
Logger(Logger const&);
Logger& operator=(Logger const&);
};
#define LOG_DEBUG(x) LogBuilder(x.get(), logging::LOG_LEVEL::debug)
#define LOG_INFO(x) LogBuilder(x.get(), logging::LOG_LEVEL::info)
#define LOG_TRACE(x) LogBuilder(x.get(), logging::LOG_LEVEL::trace)
#define LOG_ERROR(x) LogBuilder(x.get(), logging::LOG_LEVEL::err)
#define LOG_WARN(x) LogBuilder(x.get(), logging::LOG_LEVEL::warn)
} // namespace logging
} // namespace core
} // namespace minifi
} // namespace nifi
} // namespace apache
} // namespace org
#endif // LIBMINIFI_INCLUDE_CORE_LOGGING_LOGGER_H_