实现和一个类似于glog的日志管理系统
版本一:
实现功能:将日志信息记录到两个文件中, 一个文件记录ERROR和WARNNING信息,一个文件记录INFO和DEBUG信息,在程序运行前指定要存储的文件的名称。
//Logger.h
#ifndef _LOGGER_H_
#define _LOGGER_H_
#include <iostream>
#include <iomanip>
#include <fstream>
#include <string>
#include <cstdlib>
#include <stdint.h>
typedef enum rank {
ERROR,
WARNNING,
INFO,
DEBUG
}log_rank;
void SetLogDestination(const std::string& ALL_LOG_FILENAME, const std::string& ERROR_AND_WARNING_FILENAME);
class Logger {
friend void SetLogDestination(const std::string& ALL_LOG_FILENAME,
const std::string& ERROR_AND_WARNING_FILENAME);
public:
Logger() = delete;
Logger(log_rank rank);
~Logger();
static std::ostream& WriteLog(log_rank rank,
const int Line,
const std::string& Function,
const std::string& FileName);
private:
static std::ostream& GetStream (log_rank rank);
static std::ofstream m_all_log_file;
static std::ofstream m_error_and_warning_file;
log_rank m_rank;
};
class Logger_P {
public:
Logger_P() = delete;
Logger_P(log_rank rank);
~Logger_P();
static std::ostream& ShowLog(log_rank rank,
const int Line,
const std::string& Function,
const std::string& FileName);
private:
static std::ostream& GetStream(log_rank rank);
log_rank m_rank;
};
#define LOG(rank) \
Logger(rank).WriteLog(rank, __LINE__, __FUNCTION__, __FILE__)
#define LOG_P(rank) \
Logger_P(rank).ShowLog(rank, __LINE__, __FUNCTION__, __FILE__)
#endif // _LOGGER_H_
//logger.cpp
#include <cstdlib>
#include <ctime>
#include <iostream>
#include "logger.h"
std::ofstream Logger::m_all_log_file;
std::ofstream Logger::m_error_and_warning_file;
void SetLogDestination(const std::string& ALL_LOG_FILENAME, const std::string& ERROR_AND_WARNING_FILENAME) {
Logger::m_all_log_file.open(ALL_LOG_FILENAME.c_str(), std::ios::app);
Logger::m_error_and_warning_file.open(ERROR_AND_WARNING_FILENAME.c_str(), std::ios::app );
}
std::ostream& Logger::GetStream (log_rank rank) {
if (rank == ERROR or rank == WARNNING ) {
if (m_error_and_warning_file.is_open())
return m_error_and_warning_file;
else
return std::cerr;
}
else if (rank == INFO or rank == DEBUG) {
if (m_all_log_file.is_open())
return m_all_log_file;
else
return std::cout;
}
else {
std::cerr<< "Wrong Rank!!!"<< std::endl;
}
}
std::ostream& Logger::WriteLog(log_rank rank,
const int Line,
const std::string& Function,
const std::string& FileName) {
time_t tm;
time(&tm);
char time_string[128];
ctime_r(&tm, time_string);
return Logger::GetStream(rank) << std::endl <<time_string
<< "File: <" << FileName << "> "
<< " Function: <" << Function << "> "
<< " Line: " << Line << std::endl
<< "LogMessage: "
<< std::flush;
}
Logger::Logger(log_rank rank):m_rank(rank) { }
Logger::~Logger() {
Logger::GetStream(WARNNING) << std::endl << std::flush;
Logger::GetStream(INFO) << std::endl<< std::flush;
// m_all_log_file.close();
// m_error_and_warning_file.close();
}
Logger_P::Logger_P(log_rank rank):m_rank(rank) {}
Logger_P::~Logger_P() {std::cout << std::endl; }
std::ostream& Logger_P::GetStream (log_rank rank) {
if (rank == ERROR or rank == WARNNING)
return std::cerr;
else if (rank == INFO or rank == DEBUG)
return std::cout;
else
std::cerr << "Wrong Rank!!!" << std::endl;
}
std::ostream & Logger_P::ShowLog(log_rank rank,
const int Line,
const std::string& Function,
const std::string& FileName) {
time_t tm;
time(&tm);
char time_string[128];
ctime_r(&tm, time_string);
return Logger_P::GetStream(rank) << std::endl << time_string
<< "File : <" << FileName << ">"
<< " Function : <" << Function << ">"
<< " Line : " << Line<< std::endl
<< "LogMessage: "
<< std::ends;
}
//test.cpp
#include <iostream>
#include <string>
#include "logger.h"
int showwarning (){
LOG_P(WARNNING)<< "WARNNING";
LOG(WARNNING)<< "WARNNING";
return 0;
}
int showerror () {
LOG(ERROR)<< "there is something wrong!";
LOG_P(ERROR)<< "there is something wrong!";
return 0;
}
bool debug() {
LOG(DEBUG)<< "BUG Need to be resolved!";
LOG_P(DEBUG)<< "BUG Need to be resolved!";
return true;
}
void showinfo() {
LOG(INFO)<< "some info want to be record!";
LOG_P(INFO)<< "some info want to be record!";
}
int main()
{
SetLogDestination("all.txt","error.txt");
showwarning();
showerror();
debug();
showinfo();
return 0;
}
输出示例:
LOP_P信息LOG记录信息
版本二:
需求变更:
要求输出的log信息存储到两个文件中,一个文件用来存储ERROR和WARNNING信息,一个文件用来存储所有的log信息,并根据环境变量来决定记录到的等级,等级按ERROR,WARNNIGN,INFO,DEBUG排序,等级最低的时候只记录ERROR信息等级最高的时候记录所有的信息。并要求有多线程安全的机制。
//logger.h
#ifndef _LOGGER_H_
#define _LOGGER_H_
#include <iostream>
#include <fstream>
#include <string>
#include <array>
#include <cstdlib>
#include "spinlock.h"
typedef enum rank {
ERROR,
WARNNING,
INFO,
DEBUG
}log_rank;
class Logger {
public:
static void SetLogPattern(const bool& to_screen, const bool& to_file);
static Logger* GetInstance();
public:
~Logger();//close file
Logger(const Logger&) = delete;
Logger& operator = (const Logger&) = delete;
void Record(log_rank rank, const int line, const std::string FileName,const std::string info);
private:
Logger();//open file
void StreamWriter (log_rank rank);
void StoreInfo(const std::string info, const int line, const std::string filename);
void InfoWriter(std::ostream &stream_out, log_rank rank);
private:
static bool out_to_screen_;
static bool out_to_file_;
std::ofstream logfile_;
std::ofstream error_logfile_;
std::string info_;
int line_;
std::string filename_;
int level_;
log_rank rank_;
libstream::SpinLock lock_;
const std::array<std::string, 4> rank_arr_ = {"ERROR", "WARNNING", "ERROR", "DEBUG"};
};
#define LOG(rank, string) \
Logger::GetInstance()->Record(rank, __LINE__, __FILE__,string);
#endif // _LOGGER_H_
//logger.cpp
#include <cstdlib>
#include <ctime>
#include <iostream>
#include <string>
#include "logger.h"
bool Logger::out_to_file_ = 1;
bool Logger::out_to_screen_ = 1;
void Logger::SetLogPattern(const bool& to_screen, const bool& to_file) {
Logger::out_to_screen_ = to_screen;
Logger::out_to_file_ = to_file;
}
Logger* Logger::GetInstance() {
static Logger instance;
return &instance;
}
void Logger::StoreInfo(const std::string info, const int line, const std::string filename) {
info_ = info;
line_ = line;
filename_ = filename;
}
void Logger::InfoWriter(std::ostream &stream_out, log_rank rank) {
time_t tm;
time(&tm);
char time_string[128];
strftime(time_string, 128, "%Y %m.%d %T", localtime(&tm));
std::string str_time (time_string);
stream_out << str_time
<< " File : " << filename_
<< " Line : " << line_
<< " [" << rank_arr_[rank]<< "] "
<< info_
<< std::endl;
}
void Logger::StreamWriter (log_rank rank) {
if (rank == ERROR or rank == WARNNING) {
if (out_to_file_) {
InfoWriter(error_logfile_, rank);
InfoWriter(logfile_, rank);
}
if (out_to_screen_)
InfoWriter(std::cerr, rank);
}
else if (rank == INFO or rank == DEBUG) {
if (out_to_file_)
InfoWriter(logfile_,rank);
if (out_to_screen_)
InfoWriter(std::cout, rank);
}
else
std::cout << "Wrong rank!!!"<<std::endl;
}
void Logger::Record(log_rank rank,
const int line,
const std::string filename,
const std::string info) {
StoreInfo(info, line, filename);
libstream::SpinLockGuard lk(lock_);
switch (level_) {
case 3:
if(rank == DEBUG)
StreamWriter(DEBUG);
case 2:
if (rank == INFO)
StreamWriter(INFO);
case 1:
if (rank == WARNNING)
StreamWriter(WARNNING);
case 0:
if (rank == ERROR)
StreamWriter(ERROR);
}
}
// open file
Logger::Logger() {
char * level = getenv("LEVEL");
if (level == nullptr)
level_ = 1;
else{
level_ = level[0] - '0';
if (level_ <0 or level_>3){
std::cerr << "The CNSTREAM_TOOLKIT_LOG_LEVEL must have a value between 0 and 5"<< std::endl;
level_ = 1;
}
}
time_t tm;
time(&tm);
char time_string[128];
strftime(time_string, 128, "Logfile_%Y-%m.%d-%T", localtime(&tm));
std::string str_name(time_string);
logfile_.open((str_name + ".log").c_str());
error_logfile_.open((str_name + "_error.log").c_str());
}
//close file
Logger::~Logger() {
logfile_.close();
error_logfile_.close();
}
//spinlock.h
#ifndef SPIN_LOCK_H_
#define SPIN_LOCK_H_
#include <atomic>
class SpinLock {
public:
void lock() {
while (lock_.test_and_set(std::memory_order_acquire)) {
}
}
void unlock() { lock_.clear(std::memory_order_release); }
private:
std::atomic_flag lock_ = ATOMIC_FLAG_INIT;
};
class SpinLockGuard {
public:
explicit SpinLockGuard(SpinLock &lock) : lock_(lock) { lock_.lock(); }
~SpinLockGuard() { lock_.unlock(); }
private:
SpinLock &lock_;
};
#endif // SPIN_LOCK_H_
//test.cpp
#include <iostream>
#include <string>
#include "logger.h"
int showwarning (){
LOG(WARNNING, "WARNNING");
return 0;
}
int showerror () {
LOG(ERROR, "there is something wrong!");
return 0;
}
bool debug() {
LOG(DEBUG, "BUG Need to be resolved!");
return true;
}
void showinfo() {
LOG(INFO, "some info want to be record!");
}
int main()
{
Logger::SetLogPattern(0,1);
showwarning();
showerror();
debug();
showinfo();
return 0;
}
注:SetLogPattern(param1,param2)
param1:决定是否将日志信息以jcout或cerr的形式输出到屏幕
param2:决定是否将日志信息记录到文件中
编译运行:
编译运行注:LEVEL是给定环境变量:根据环境变量决定打印的等级:
LEVEL =0 : 只输出ERROR信息
LEVEL =1 : 输出ERROE和WARNNING信息
LEVEL =2 : 输出ERROR,WARNNING和INFO信息
LEVEL =3 : 输出ERROR,WARNNING,INFO和DEBUG信息
网友评论