logger.h
#pragma once
#include <atomic>
#include <chrono>
#include <fstream>
#include <mutex>
#include <sstream>
#include <string>
#include <string_view>
#include "fmt/chrono.h"
#include "fmt/format.h"
#include "singleton.h"
#define LOG_DEBUG(_fmt, ...) \
flower::logger::instance().write(flower::logger::llt_debug, \
fmt::format("{:%y-%m-%d %H:%M:%S} [DEBUG] " _fmt "\n", \
std::chrono::high_resolution_clock::now(), ##__VA_ARGS__))
#define LOG_INFO(_fmt, ...) \
flower::logger::instance().write(flower::logger::llt_info, \
fmt::format("{:%y-%m-%d %H:%M:%S} [INFO] " _fmt "\n", \
std::chrono::high_resolution_clock::now(), ##__VA_ARGS__))
#define LOG_WARN(_fmt, ...) \
flower::logger::instance().write(flower::logger::llt_warn, \
fmt::format("{:%y-%m-%d %H:%M:%S} [WARN] " _fmt "\n", \
std::chrono::high_resolution_clock::now(), ##__VA_ARGS__))
#define LOG_ERROR(_fmt, ...) \
flower::logger::instance().write(flower::logger::llt_error, \
fmt::format("{:%y-%m-%d %H:%M:%S} [ERROR] " _fmt "\n", \
std::chrono::high_resolution_clock::now(), ##__VA_ARGS__))
namespace flower {
class logger final : public singleton<logger> {
friend class singleton<logger>;
public:
enum log_level_type {
llt_debug = 0,
llt_info,
llt_warn,
llt_error,
llt_off,
};
enum log_type {
lt_none,
lt_file,
lt_console,
};
private:
logger();
public:
~logger() override {
close_file();
}
bool start(std::string_view log_dir, std::string_view file_prefix, uint16_t file_level, uint16_t console_level);
void set_log_level(log_type ty, log_level_type level);
void write(log_level_type level, std::string_view log);
void flush() {
std::lock_guard lock(mutex_);
file_.flush();
}
private:
void close_file();
bool create_log_file();
void check_file_name();
private:
std::string file_prefix_{};
std::atomic_uint16_t day_{};
std::ofstream file_{};
std::string log_dir_{};
std::atomic_uint16_t file_level_{};
std::atomic_uint16_t console_level_{};
std::mutex mutex_{};
};
} // namespace flower
logger.cpp
#include "logger.h"
#include "comm_func.h"
namespace flower {
logger::logger()
: file_level_(log_level_type::llt_off)
, console_level_(log_level_type::llt_debug) {
}
bool logger::start(std::string_view log_dir, std::string_view file_prefix, uint16_t file_level,
uint16_t console_level) {
{
std::lock_guard lock(mutex_);
log_dir_ = log_dir;
file_level_ = file_level;
console_level_ = console_level;
file_prefix_ = file_prefix;
std::string path = comm_func::get_current_exe_dir();
path.append("/").append(log_dir_);
log_dir_ = path;
if (!comm_func::create_dir(log_dir_)) {
LOG_ERROR("logger::start create dir error");
return false;
}
}
return true;
}
void logger::set_log_level(log_type ty, log_level_type level) {
if (ty == log_type::lt_file) {
file_level_ = level;
if (file_level_ == log_level_type::llt_off) {
day_ = 0;
close_file();
}
} else if (ty == log_type::lt_console) {
console_level_ = level;
} else {
}
}
void logger::write(log_level_type level, std::string_view log) {
if (file_level_ <= level) {
check_file_name();
std::lock_guard lock(mutex_);
file_ << log;
}
if (console_level_ <= level) {
std::cout << log.data();
}
}
void logger::close_file() {
std::lock_guard lock(mutex_);
if (file_.is_open()) {
file_.flush();
file_.close();
}
}
bool logger::create_log_file() {
{
std::lock_guard lock(mutex_);
std::string log_file_name =
fmt::format("{}/{}_{:%Y_%m_%d}.log", log_dir_, file_prefix_, std::chrono::high_resolution_clock::now());
file_.open(log_file_name, std::ios::app);
if (file_.fail()) {
std::cout << "logger::create_log_file file:" << log_file_name << " open failed." << std::endl;
return false;
}
}
day_ = comm_func::get_month_day();
return true;
}
void logger::check_file_name() {
if (day_ != comm_func::get_month_day()) {
close_file();
create_log_file();
}
}
} // namespace flower