这里是自己总结简易的日志代码,当只需要一个简易的日志库记录日志时,调试程序时只需要包含此Logger.hpp 并没考虑性能和太复杂运行情况
- 支持只写文件也支持只打印,同时也支持,功能可自行通过构造参数设置
- 默自动创建Log目录,同时按时间名自动创建日志文件
- 支持不同级别日志记录,同时打印窗口支持不同级别不同颜色显示Log信息
- 支持日志记录代码文件名和行号和行号
Windows平台测试通过,Linux暂未测试 纯C++版本
#ifndef LOGGER_HPP
#define LOGGER_HPP
// 这里是你的Logger.hpp文件的内容
#include <iostream>
#include <fstream>
#include <ctime>
#include <string>
#include <iomanip>
#include <direct.h> // Windows 下创建目录所需的头文件
// 在 Linux 下创建目录需要使用 <sys/stat.h> 头文件
class LogLevel {
public:
enum Level {
Debug, // 调试级别
Info, // 信息级别
Warning, // 警告级别
Error // 错误级别
};
};
class Logger {
public:
// 构造函数,用于初始化日志对象
Logger(bool enableConsoleOutput = true, bool enableFileOutput = true)
: m_enableConsoleOutput(enableConsoleOutput), m_enableFileOutput(enableFileOutput)
{
// 检查 log 文件夹是否存在,如果不存在则创建它
std::string logDir = "log";
#ifdef _WIN32
_mkdir(logDir.c_str()); // Windows 下创建目录
#else
mkdir(logDir.c_str(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH); // Linux 下创建目录
#endif
// 创建日志文件名,格式为 "log_年月日_时分秒.txt"
std::time_t t = std::time(nullptr);
char timestamp[20]; // 用于存储格式化后的时间字符串
std::tm tm;
localtime_s(&tm, &t); // 将时间戳转换为本地时间
std::strftime(timestamp, sizeof(timestamp), "%Y-%m-%d_%H-%M-%S", &tm); // 将时间格式化为字符串
m_filePath = logDir + "/log_" + timestamp + ".txt";
if (m_enableFileOutput)
{
m_file.open(m_filePath.c_str(), std::ios_base::out | std::ios_base::app); // 打开日志文件
}
}
// 析构函数,用于关闭日志文件
~Logger()
{
if (m_enableFileOutput)
{
m_file.close(); // 关闭日志文件
}
}
// 设置日志级别
void setLogLevel(LogLevel::Level level)
{
m_logLevel = level;
}
// 输出调试信息
void debug(const std::string& message, const char* file = nullptr, int line = -1)
{
log(LogLevel::Debug, message, file, line);
}
// 输出普通信息
void info(const std::string& message, const char* file = nullptr, int line = -1)
{
log(LogLevel::Info, message, file, line);
}
// 输出警告信息
void warning(const std::string& message, const char* file = nullptr, int line = -1)
{
log(LogLevel::Warning, message, file, line);
}
// 输出错误信息
void error(const std::string& message, const char* file = nullptr, int line = -1)
{
log(LogLevel::Error, message, file, line);
}
private:
bool m_enableConsoleOutput; // 是否输出到控制台
bool m_enableFileOutput; // 是否输出到文件
std::string m_filePath; // 日志文件路径
std::ofstream m_file; // 日志文件对象
LogLevel::Level m_logLevel = LogLevel::Info; // 日志级别,默认为 Info
// 内部函数,用于输出日志信息
void log(LogLevel::Level level, const std::string& message, const char* file = nullptr, int line = -1)
{
if (level < m_logLevel) // 如果日志级别低于设定的级别,则不输出
{
return;
}
std::string logLevelStr; // 日志级别字符串
std::string colorCode; // 控制台输出颜色代码
switch (level)
{
case LogLevel::Debug:
logLevelStr = "DEBUG";
colorCode = "\033[36m"; // 青色
break;
case LogLevel::Info:
logLevelStr = "INFO";
colorCode = "\033[32m"; // 绿色
break;
case LogLevel::Warning:
logLevelStr = "WARNING";
colorCode = "\033[33m"; // 黄色
break;
case LogLevel::Error:
logLevelStr = "ERROR";
colorCode = "\033[31m"; // 红色
break;
default:
logLevelStr = "UNKNOWN";
break;
}
std::string output;
if (file == nullptr || line == -1) // 如果没有文件名和行号,则只输出时间、级别和消息
{
output = "[" + getCurrentTime() + "]" + " [" + logLevelStr + "]" + " " + message + "\n";
}
else // 如果有文件名和行号,则输出时间、级别、文件名、行号和消息
{
std::string fileName(file);
fileName = fileName.substr(fileName.find_last_of("/\\") + 1); // 获取文件名
output = "[" + getCurrentTime() + "]" + " [" + logLevelStr + "]" + " [" + fileName + ":" + std::to_string(line) + "]" + " " + message + "\n";
}
// 输出到控制台
if (m_enableConsoleOutput)
{
std::cout << colorCode << output << "\033[0m"; // 输出带颜色的日志信息
}
// 输出到文件
if (m_enableFileOutput && m_file)
{
m_file << output; // 将日志信息写入文件
m_file.flush(); // 将缓冲区的数据立即写入文件
}
}
// 获取当前时间
std::string getCurrentTime()
{
char timeStr[30]; // 用于存储格式化后的时间字符串
std::time_t t = std::time(nullptr); // 获取当前时间戳
std::tm tm;
localtime_s(&tm, &t); // 将时间戳转换为本地时间
std::strftime(timeStr, sizeof(timeStr), "%Y-%m-%d %H:%M:%S", &tm); // 将时间格式化为字符串
return std::string(timeStr); // 将字符数组转换为 std::string 对象并返回
}
};
#endif
测试例子
int main()
{
//1.开启控制台打印 2.开启文件写入
Logger m_log(true,true);
//记录代码文件名和代码行
m_log.info("hell world", __FILE__, __LINE__);
m_log.warning("hell world", __FILE__, __LINE__);
m_log.error("hell world");
m_log.debug("hell world");
std::cout << "Hello World!\n";
}
运行截图
Qt版本
#ifndef LOGGER_HPP
#define LOGGER_HPP
#include <QDir>
#include <QFile>
#include <QTextStream>
#include <QDateTime>
#include <QDebug>
class Logger
{
public:
enum LogLevel
{
Debug,
Info,
Warning,
Error
};
Logger(bool enableConsoleOutput = true, bool enableFileOutput = true)
: m_enableConsoleOutput(enableConsoleOutput), m_enableFileOutput(enableFileOutput)
{
// 检查 log 文件夹是否存在,如果不存在则创建它
QString logDir = QDir::currentPath() + "/log";
if (!QDir(logDir).exists())
{
QDir().mkpath(logDir);
}
// 创建日志文件名,格式为 "log_年月日_时分秒.txt"
QString timestamp = QDateTime::currentDateTime().toString("yyyy-MM-dd_hh-mm-ss");
m_filePath = QString("%1/log_%2.txt").arg(logDir).arg(timestamp);
if (m_enableFileOutput)
{
m_file = new QFile(m_filePath);
m_file->open(QIODevice::WriteOnly | QIODevice::Append | QIODevice::Text);
}
}
~Logger()
{
if (m_enableFileOutput)
{
m_file->close();
delete m_file;
}
}
void setLogLevel(LogLevel level)
{
m_logLevel = level;
}
void debug(const QString &message, const char *file = Q_NULLPTR, int line = -1)
{
log(Debug, message, file, line);
}
void info(const QString &message, const char *file = Q_NULLPTR, int line = -1)
{
log(Info, message, file, line);
}
void warning(const QString &message, const char *file = Q_NULLPTR, int line = -1)
{
log(Warning, message, file, line);
}
void error(const QString &message, const char *file = Q_NULLPTR, int line = -1)
{
log(Error, message, file, line);
}
private:
bool m_enableConsoleOutput; // 是否输出到控制台
bool m_enableFileOutput; // 是否输出到文件
QString m_filePath; // 日志文件路径
QFile *m_file; // 日志文件对象
LogLevel m_logLevel = Info; // 日志级别,默认为 Info
void log(LogLevel level, const QString &message, const char *file, int line)
{
if (level < m_logLevel)
{
return;
}
QString logLevelStr;
QString colorCode;
switch (level)
{
case Debug:
logLevelStr = "DEBUG";
colorCode = "\033[36m"; // 青色
break;
case Info:
logLevelStr = "INFO";
colorCode = "\033[32m"; // 绿色
break;
case Warning:
logLevelStr = "WARNING";
colorCode = "\033[33m"; // 黄色
break;
case Error:
logLevelStr = "ERROR";
colorCode = "\033[31m"; // 红色
break;
default:
logLevelStr = "UNKNOWN";
break;
}
QString output;
if (file == Q_NULLPTR || line == -1)
{
output = QString("%1[%2]%3 %4\033[0m\n")
.arg(colorCode)
.arg(QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss.zzz"))
.arg(logLevelStr)
.arg(message);
}
else
{
output = QString("%1[%2][%3:%4]%5 %6\033[0m\n")
.arg(colorCode)
.arg(QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss.zzz"))
.arg(QFileInfo(file).fileName())
.arg(line)
.arg(logLevelStr)
.arg(message);
}
if (m_enableConsoleOutput)
{
qInfo().noquote() << output;
}
if (m_enableFileOutput && m_file)
{
QTextStream stream(m_file);
stream << QString("[%1][%2] %3\n").arg(QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss.zzz")).arg(logLevelStr).arg(message);
m_file->flush();
}
}
};
#endif