可配日志输出
log.h
#ifndef LOG_H
#define LOG_H#include <iostream>#ifndef LOG_TYPE
#define LOG_TYPE
//日志类型
enum LogType
{ErrorLog = 0, //错误WarnLog , //告警InfoLog, //信息DebugLog //调试
};
#endifstd::string getCurrentTime();
void writeLog(int type, const char* format, ...);#define LOG(level, fmt, ...) writeLog(level,"[%s][%s][%d][%s] " fmt" ", getCurrentTime().c_str(), __FILE__, __LINE__, __FUNCTION__, ##__VA_ARGS__)#define LOG_DEBUG(fmt, ...) writeLog(DebugLog,"[%s][%s][%d][%s][DEBUG] " fmt" ", getCurrentTime().c_str(), __FILE__, __LINE__, __FUNCTION__, ##__VA_ARGS__)
#define LOG_INFO(fmt, ...) writeLog(InfoLog,"[%s][%s][%d][%s][INFO] " fmt" ", getCurrentTime().c_str(), __FILE__, __LINE__, __FUNCTION__, ##__VA_ARGS__)
#define LOG_WARN(fmt, ...) writeLog(WarnLog,"[%s][%s][%d][%s][WARN] " fmt" ", getCurrentTime().c_str(), __FILE__, __LINE__, __FUNCTION__, ##__VA_ARGS__)
#define LOG_ERROR(fmt, ...) writeLog(ErrorLog,"[%s][%s][%d][%s][ERROR] " fmt" ", getCurrentTime().c_str(), __FILE__, __LINE__, __FUNCTION__, ##__VA_ARGS__)#endif // LOG_H
log.cpp
#include "log.h"#include <stdio.h>
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>#include <chrono>
#include <iomanip>
#include <ctime>
#include <sstream>
#include <fstream>
#include <string>
#include <algorithm>
#include <mutex>#ifdef _WIN32
#include <windows.h>
#else
#include <unistd.h>
#include <limits.h>
#include<direct.h> //头文件
#endifenum LogOutType
{OutCmd=0, //输出到终端OutFile, //输出到文件OutAll //都输出
};enum LogFileType
{FileAppend=0,//追加FileNew //重新创建,按序号命名
};#define LOG_CFG "/log.cfg"
#define LOG_DIR "/Logs/"
std::string g_root_path;
std::string g_log_file = "log.txt";
int g_type = WarnLog;
int g_log_file_type = FileAppend;
int g_log_out_type = OutAll;
std::mutex g_mutex;std::string getCurrentTime()
{// 获取系统时钟的当前时间点auto now = std::chrono::system_clock::now();// 转换为time_t(秒级精度)auto now_c = std::chrono::system_clock::to_time_t(now);// 转换为本地时间结构体std::tm local_tm = *std::localtime(&now_c);// 计算毫秒部分auto ms = std::chrono::duration_cast<std::chrono::milliseconds>(now.time_since_epoch()) % 1000;// 格式化为字符串std::stringstream oss;oss << std::put_time(&local_tm, "%Y-%m-%d %H:%M:%S")<< '.' << std::setfill('0') << std::setw(3) << ms.count();return oss.str();
}std::string getCurrentDir()
{static bool b_init = false;if(b_init){return g_root_path;}b_init = true;#ifdef _WIN32char buffer[MAX_PATH];GetModuleFileNameA(NULL, buffer, MAX_PATH);std::string::size_type pos = std::string(buffer).find_last_of("\\/");g_root_path = std::string(buffer).substr(0, pos);std::replace(g_root_path.begin(), g_root_path.end(), '\\', '\/');
#elsechar buffer[PATH_MAX];if (getcwd(buffer, sizeof(buffer)) != nullptr) {g_root_path = std::string(buffer);}
#endifstd::cout << "g_root_path:"<<g_root_path + LOG_DIR<<std::endl;return g_root_path;
}void initCfg()
{static bool b_init =false;if(b_init){return;}b_init = true;//初始化日志配置std::ifstream file(getCurrentDir() + LOG_CFG);if(!file.is_open()){std::cerr << "open file " <<getCurrentDir() + LOG_CFG << " error"<<std::endl;return;}try {std::string strLine;while (std::getline(file, strLine)) {//去除空格strLine.erase(std::remove(strLine.begin(), strLine.end(), ' '), strLine.end());if(strLine[0] == '#'){continue;}int index = strLine.find('=');if(index == std::string::npos){continue;}std::string key = strLine.substr(0, index);std::string value;int index_end = strLine.find('#');if(index_end == std::string::npos){value = strLine.substr(index + 1, strLine.size() - index);}else{value = strLine.substr(index + 1, index_end - index - 1);}if(key == "LogType"){g_type = std::stoi(value);}else if(key == "LogFileType"){g_log_file_type = std::stoi(value);}else if(key == "LogFileName"){g_log_file = value;}else if(key == "LogOutType"){g_log_out_type = std::stoi(value);}}} catch (std::exception &e) {std::cerr << e.what();}std::cout << "g_type:"<< g_type << std::endl<< "g_log_file_type:"<< g_log_file_type << std::endl<< "g_log_file:"<< g_log_file << std::endl<<"g_log_out_type:" <<g_log_out_type<< std::endl;file.close();
}void getLogFileNameNumberSuffix(const std::string log_file, std::string &name, int &number, std::string &suffix)
{int index = log_file.find('_');int index_suffix = log_file.find('.');//文件名if(index_suffix == std::string::npos && index == std::string::npos){name = log_file;number = 0;suffix = "";}else if(index == std::string::npos){//没有找到 '_'name = log_file.substr(0, index_suffix);number = 0;suffix = log_file.substr(index_suffix, log_file.size() - index_suffix);}else if(index_suffix == std::string::npos){//没有找到 '.'name = log_file.substr(index, log_file.size() - index);number = std::stoi(log_file.substr(index + 1, log_file.size() - index - 1));suffix = "";}else{name = log_file.substr(0, index);number = std::stoi(log_file.substr(index + 1, index_suffix - index - 1));suffix = log_file.substr(index_suffix, log_file.size() - index_suffix);}
}void initLogFile()
{static bool b_init = false;if(b_init){return;}b_init = true;if(g_log_file_type == FileNew){while(std::ifstream((getCurrentDir() + LOG_DIR + g_log_file)).good()){std::string name;int number;std::string suffix;getLogFileNameNumberSuffix(g_log_file, name, number, suffix);g_log_file = name + "_" + std::to_string(number + 1) + suffix;}}
}void writeLogFile(const char* filename, const char* log, int type)
{FILE* stream = fopen(filename, "a");if (NULL == stream) {
#ifdef _WIN32bool flag = CreateDirectoryA((g_root_path + LOG_DIR).c_str(), NULL);
#elsemkdir(g_root_path.c_str());
#endif}stream = fopen(filename, "a");if (NULL == stream) {return;}fprintf(stream,"%s\n", log);fclose(stream);
}void writeLog(int type, const char* format, ...)
{std::lock_guard<std::mutex> lock(g_mutex);initCfg();initLogFile();//判断日志类型,是否输出if(type > g_type){return;}va_list ap;va_start(ap, format);int len = vsnprintf(nullptr, 0, format, ap);char *buf = (char*)malloc(len);int rec = vsprintf(buf, format, ap);va_end(ap);switch (g_log_out_type) {case 0:printf("%s\n", buf);break;case 1:writeLogFile((getCurrentDir() + LOG_DIR + g_log_file).c_str(), buf, type);break;default:printf("%s\n", buf);writeLogFile((getCurrentDir() + LOG_DIR + g_log_file).c_str(), buf, type);break;}free(buf);
}
main.cpp
#include <QCoreApplication>
#include "log.h"
#include <iostream>
int main(int argc, char *argv[])
{QCoreApplication a(argc, argv);LOG(InfoLog, "LOG:%s %d","LOG", 11);LOG_DEBUG("LOG_DEBUG:%s %d","LOG_DEBUG", 11);LOG_INFO("LOG_INFO:%s %s","LOG_DEBUG","LOG_DEBUG");LOG_WARN("LOG_WARN:%s %d %d %s","LOG_DEBUG", 11, 22, "asda");LOG_ERROR("LOG_ERROR:%s %d %s %d","LOG_DEBUG", 11, "asd", 22);return a.exec();
}
log.cfg
LogType=2 #0:错误 1:告警 2:信息 3:调试
LogFileType = 1 #0:追加 1:重新创建
LogFileName = logg.txt #日志文件名称
LogOutType = 0 #0:输出到终端 1:输出到文件 2:都输出
终端输出
日志文件