自己动手写一个C++日志库
logger.h
| |
| |
| |
| |
| #pragma once |
| |
| #include <string> |
| #include <iostream> |
| #include <fstream> |
| #include <chrono> |
| #include <sstream> |
| |
| namespace fkkt { |
| |
| class logger { |
| public: |
| |
| enum log_level { |
| D, |
| I, |
| W, |
| E |
| }; |
| |
| |
| |
| |
| |
| |
| |
| |
| explicit logger(const std::string &log_file_name = "app", |
| log_level default_console_log_level = D, |
| const std::ios_base::openmode &mode = std::ios_base::app); |
| |
| ~logger(); |
| |
| |
| |
| |
| |
| |
| void set_console_log_level(log_level level); |
| |
| template<typename... Args> |
| void d(Args... args) { |
| std::ostringstream oss; |
| append(oss, args...); |
| write(D, oss.str()); |
| } |
| |
| template<typename... Args> |
| void i(Args... args) { |
| std::ostringstream oss; |
| append(oss, args...); |
| write(I, oss.str()); |
| } |
| |
| template<typename... Args> |
| void w(Args... args) { |
| std::ostringstream oss; |
| append(oss, args...); |
| write(W, oss.str()); |
| } |
| |
| template<typename... Args> |
| void e(Args... args) { |
| std::ostringstream oss; |
| append(oss, args...); |
| write(E, oss.str()); |
| } |
| |
| private: |
| std::ofstream log_file; |
| log_level console_log_level; |
| |
| static std::string get_log_level(log_level level); |
| |
| static std::string get_current_time_stamp(); |
| |
| void write(log_level level, const std::string &message); |
| |
| void append(std::ostringstream &oss) {} |
| |
| template<typename T, typename... Args> |
| void append(std::ostringstream &oss, const T &first, Args... args) { |
| oss << first; |
| append(oss, args...); |
| } |
| |
| }; |
| } |
logger.cpp
| |
| |
| |
| #include "logger.h" |
| #include <iostream> |
| #include <ctime> |
| #include <iomanip> |
| #include <fstream> |
| #include <mutex> |
| |
| namespace fkkt { |
| logger::logger(const std::string &log_file_name, |
| log_level default_console_log_level, |
| const std::ios_base::openmode &mode) : console_log_level(default_console_log_level) { |
| log_file.open(log_file_name, mode); |
| if (!log_file.is_open()) { |
| throw std::runtime_error("Failed to open log file: " + log_file_name); |
| } |
| std::ios::sync_with_stdio(false); |
| set_console_log_level(W); |
| } |
| |
| logger::~logger() { |
| if (log_file.is_open()) { |
| log_file.close(); |
| } |
| std::ios::sync_with_stdio(true); |
| } |
| |
| void logger::set_console_log_level(log_level level) { |
| console_log_level = level; |
| } |
| |
| std::string logger::get_log_level(log_level level) { |
| switch (level) { |
| case D: |
| return "DEBUG"; |
| case I: |
| return "INFO"; |
| case W: |
| return "WARNING"; |
| case E: |
| return "ERROR"; |
| default: |
| return "UNKNOWN"; |
| } |
| } |
| |
| std::string logger::get_current_time_stamp() { |
| auto currentTime = std::chrono::system_clock::now(); |
| auto currentTimeT = std::chrono::system_clock::to_time_t(currentTime); |
| auto timeInfo = *std::localtime(¤tTimeT); |
| std::stringstream ss; |
| ss << std::put_time(&timeInfo, "%Y-%m-%d %H:%M:%S"); |
| return ss.str(); |
| } |
| |
| void logger::write(log_level level, const std::string &message) { |
| std::lock_guard<std::mutex> lock(std::mutex); |
| std::string logMessage = get_current_time_stamp() + " [" + get_log_level(level) + "] " + message + "\n"; |
| if (level >= console_log_level) { |
| std::cout << logMessage; |
| } |
| if (log_file.is_open()) { |
| log_file << logMessage; |
| } |
| } |
| |
| } |
使用方法
| #include "logger.h" |
| |
| int main() { |
| |
| auto log = make_unique<fkkt::logger>("app.log", fkkt::logger::log_level::D, ios::in); |
| log->set_console_log_level(fkkt::logger::D); |
| log->d("Hello ", 10924); |
| |
| return 0; |
| } |
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· 三行代码完成国际化适配,妙~啊~
· .NET Core 中如何实现缓存的预热?