单例模式(Singleton Pattern)是一种常用的设计模式,旨在确保一个类只有一个实例,并提供一个全局访问点来获取该实例。单例模式用于控制对某个共享资源的访问,确保在应用程序的生命周期内只有一个实例存在。
以下是单例模式的基本实现步骤:
nullptr 时创建新实例。同时要确保线程安全(尤其是在多线程环境下)。#include <iostream>
#include <mutex>
class Singleton {
public:
// 获取单例实例的静态方法
static Singleton& getInstance() {
static Singleton instance; // 饿汉式,保证线程安全
return instance;
}
// 公共方法供外部使用
void showMessage() {
std::cout << "Hello, Singleton!" << std::endl;
}
private:
// 私有构造函数
Singleton() {
std::cout << "Singleton created!" << std::endl;
}
// 禁止拷贝构造函数和赋值操作符
Singleton(const Singleton&) = delete;
Singleton& operator=(const Singleton&) = delete;
};
int main() {
// 获取单例实例并调用方法
Singleton::getInstance().showMessage();
return 0;
}
在多线程环境下,单例模式的实现需要特别小心。一个常见的方式是使用 std::mutex 进行加锁,以确保初始化的线程安全。但更简单的实现是使用局部静态变量,这在 C++11 及以上版本中是线程安全的,因为其构造保证了只会被调用一次
spdlog.h
#ifndef _LOGGER_H_
#define _LOGGER_H_
#include <mutex>
#include <memory>
//#include <QtGlobal>
#include "spdlog/spdlog.h"
#include "spdlog/async.h"
#include "spdlog/sinks/stdout_color_sinks.h" // or "../stdout_sinks.h" if no color needed
#include "spdlog/sinks/basic_file_sink.h"
#include "spdlog/sinks/rotating_file_sink.h"
#include "spdlog/sinks/udp_sink.h"
#include "spdlog/fmt/bin_to_hex.h"
//#include "ShortWaveConfig.h"
#define BUFFER_PER_DEAL(buffer, size) \
std::vector<char> buf; \
for (int i=0;i<size;i++) \
{ \
buf.push_back(static_cast<char>(buffer[i] & 0xff)); \
}
class CLogger
{
protected:
CLogger();
~CLogger();
CLogger(const CLogger&)= delete;
CLogger& operator = (const CLogger&) = delete;
//日志记录器类,采用单例模式设计。
public:
static CLogger* getInstance()
{
if(m_plogger == nullptr)
{
std::unique_lock<std::mutex> lock(m_mutex); //加锁,保证线程安全
if(m_plogger == nullptr)
m_plogger = new CLogger();
}
return m_plogger;
}// 获取logger实例的静态方法。
public:
std::shared_ptr<spdlog::logger> getLogger()
{
return m_pfilelogger;
} // 返回logger的方法,返回一个指向spdlog::logger的共享指针,供外部使用和调用日志。
private:
static void freeLoggerPtr();
void unInit();
void initEx();
private:
static std::mutex m_mutex; //静态互斥量
static CLogger* m_plogger; //静态指针,用于存储唯一的Clogger实例
std::shared_ptr<spdlog::logger> m_pfilelogger;
};
// use embedded macro to support file and line number
#define UVLOG_TRACE(...) SPDLOG_LOGGER_CALL(CLogger::getInstance()->getLogger().get(), spdlog::level::trace, __VA_ARGS__)
#define UVLOG_DEBUG(...) SPDLOG_LOGGER_CALL(CLogger::getInstance()->getLogger().get(), spdlog::level::debug, __VA_ARGS__)
#define UVLOG_INFO(...) SPDLOG_LOGGER_CALL(CLogger::getInstance()->getLogger().get(), spdlog::level::info, __VA_ARGS__)
#define UVLOG_WARN(...) SPDLOG_LOGGER_CALL(CLogger::getInstance()->getLogger().get(), spdlog::level::warn, __VA_ARGS__)
#define UVLOG_ERROR(...) SPDLOG_LOGGER_CALL(CLogger::getInstance()->getLogger().get(), spdlog::level::err, __VA_ARGS__)
/***********************************************************************************
//格式化的例子:
UVLOG_INFO("print data,{},{}", 1000, "hello!");
UVLOG_INFO("Hello, {}!", "World");
UVLOG_INFO("Welcome to spdlog!");
UVLOG_ERROR("Some error message with arg: {}", 1);
UVLOG_WARN("Easy padding in numbers like {:08d}", 12);
UVLOG_INFO("Support for int: {0:d}; hex: {0:x}; oct: {0:o}; bin: {0:b}", 42);
UVLOG_INFO("Support for floats {:03.2f}", 1.23456);
UVLOG_INFO("Positional args are {1} {0}..", "too", "supported");
UVLOG_INFO("{:<30}", "left aligned");
**********************************************************************************/
#endif
logger.cpp
//#include "stdafx.h"
#include "Logger.h"
#include <iostream>
std::mutex CLogger::m_mutex;
CLogger* CLogger::m_pLogger = nullptr;
CLogger::CLogger()
: m_pFileLogger(nullptr)
{
//[1]
//m_LogConfig.loadConfig();
//[2]
//init();
initEx();
//[N]
atexit(freeLoggerPtr); //注册清理函数,在程序退出时调用freeLoggerPtr。
}
CLogger::~CLogger()
{
unInit();
}
void CLogger::freeLoggerPtr()
{
if (m_pLogger) {
delete m_pLogger;
}
}
void CLogger::unInit()
{
spdlog::drop_all(); //spdlog提供的函数,用于清理所有的日志记录器和释放相关资源。
}
void CLogger::initEx()
{
try
{
auto max_size = 1048576 * 50; //每个日志文件大小
auto max_files = 3; //最多保留三个日志文件
auto pFileLogger = std::make_shared<spdlog::sinks::rotating_file_sink_mt>("logs/test_log.txt", max_size, max_files); //rotating_file_sink_mt是spdlog提供的多线程安全的日志记录器。
pFileLogger->set_pa
ttern("%Y-%m-%d %H:%M:%S.%f <thread %t> [%l] %v"); //设置格式,前面是时间戳,<thread %t>打印线程ID,[%l] 打印线程级别 %v打印日志内容
pFileLogger->set_level(spdlog::level::info);
#if 0
spdlog::sinks::udp_sink_config config(m_LogConfig.m_remoteServerIP, m_LogConfig.m_remoteServerPort);
auto pUdpLogger = std::make_shared<spdlog::sinks::udp_sink_mt>(config);
pUdpLogger->set_pattern("%Y-%m-%d %H:%M:%S.%f <thread %t> [%l] [%@] %v");
pUdpLogger->set_level(spdlog::level::info);
std::vector< spdlog::sink_ptr> sinks = { pFileLogger, pUdpLogger };
#else
std::vector< spdlog::sink_ptr> sinks = { pFileLogger }; //创建一个 sinks 容器,将 pFileLogger(文件日志记录器)添加到其中
#endif
m_pFileLogger = std::make_shared<spdlog::logger>("uvLinkLogger", sinks.begin(), sinks.end());
//创建 Logger: 使用 sinks 向量创建一个新的 logger 对象 uvLinkLogger
m_pFileLogger->set_level(spdlog::level::info);
m_pFileLogger->flush_on(spdlog::level::info);
}
catch (const spdlog::spdlog_ex& ex)
{
std::cout << "Log initialization failed: " << ex.what() << std::endl;
//捕获 spdlog 抛出的初始化异常,并输出错误信息。这有助于调试初始化日志系统时出现的问题。
}
}
Registry (日志记录器注册表) 用于管理所有已创建的Logger对象//代码示例
#include <iostream>
#include <fstream>
#include <string>
#include <ctime>
#include <fmt/core.h> // fmt库的核心功能,用于格式化字符串
enum LogLevel {
INFO,
WARNING,
ERROR
}; //枚举日志级别
template<typename... Args>
void log_message(LogLevel level, const std::string& format,Args... args){ //模板函数,允许接受可变数量的参数
std:: ofstream log_file("log.txt",std::ios::app); //打开一个名为log.txt的文件,模式为追加(std::ios::app)。
}
std::time_t now = std::time(nullptr); //获取当前时间。
std::string dt = std::ctime(&now); //ctime将时间转换为字符串
dt.pop_back(); //移除换行符
std::string level_str;
switch(level) {
case INFO:
level_str = "INFO";
break;
case WARNING:
level_str = "WARNING";
break;
case ERROR:
level_str = "ERROR";
break;
}
//格式化日志消息
auto formatted_message = fmt::format(format,args...); //使用 fmt::format 来格式化日志消息
auto log_entry = fmt::format("[{} {}] {}\n", dt,level_str, formatted_message); //log_entry 是最终的日志条目,包含时间戳、日志级别和格式化后的消息
log_file << log_entry;
log_file.close();
if (!log_file.is_open()) {
std::cerr << "Failed to open log file!" << std::endl;
}
int main() {
log_message(INFO, "This is an info message.");
log_message(ERROR, "Error code: {}. Error message: {}", 404, "Not Found");
return 0;
}
[Sat Mar 2 14:59:10 2024 INFO] This is an info message.
[Sat Mar 2 14:59:10 2024 ERROR] Error code: 404. Error message: Not Found
trace:最详细的日志级别,提供追踪程序执行流程的信息。
debug:调试级别的日志信息,用于调试程序逻辑和查找问题。
info:通知级别的日志信息,提供程序运行时的一般信息。
warn:警告级别的日志信息,表明可能发生错误或不符合预期的情况。
error:错误级别的日志信息,表明发生了某些错误或异常情况。
critical:严重错误级别的日志信息,表示一个致命的或不可恢复的错误。
#include "spdlog/sinks/stdout_color_sinks.h"
int main() {
auto logger = spdlog::stdout_color_mt("console");
//spdlog::stdout_color_mt 创建了一个多线程安全的 (multi-thread) 彩色输出 logger,命名为 "console"。这里使用 auto 关键字自动推断 logger 的类型。
//这个 logger 将输出日志消息到控制台,并且消息将以不同的颜色显示,取决于日志级别。
logger->set_level(spdlog::level::warn);
//set_level 方法设置了这个 logger 的日志级别为 warn,这意味着只有警告级别及以上的日志消息会被记录并输出。spdlog::level::warn 表示日志级别为警告,因此,trace 和 debug 的日志消息将不会被输出。
logger->trace("trace message");
logger->debug("debug message");
logger->info("info message");
logger->warn("warn message");
logger->error("error message");
logger->critical("critical message");
return 0;
}
sink 和 logger 是 spdlog 库中两个核心概念,它们承担不同的角色并且各自有不同的功能。以下是这两个概念的区别:
Sink (输出目标)
:
spdlog::sinks::stdout_sink_mt:将日志输出到控制台标准输出。spdlog::sinks::daily_file_sink_mt:将日志输出到每日日志文件。spdlog::sinks::rotating_file_sink_mt:将日志输出到滚动文件,支持设置最大文件大小和文件数量。Logger (记录器)
:
为了更好理解它们的区分,下面是一个简单的示例,展示如何在 spdlog 中使用 sink 和 logger。
cpp#include "spdlog/spdlog.h"
#include "spdlog/sinks/daily_file_sink.h"
int main() {
// 创建一个每天自动滚动的日志 sink
auto sink = std::make_shared<spdlog::sinks::daily_file_sink_mt>("my_log.log", 23, 59);
// 创建一个 logger,并绑定到创建的 sink
auto logger = std::make_shared<spdlog::logger>("daily_logger", sink);
// 设置日志级别
logger->set_level(spdlog::level::info);
// 记录一些日志信息
logger->info("This is an info message.");
logger->warn("This is a warning message.");
return 0;
}
在这个示例中:
sink 是一个指向 daily_file_sink_mt 的共享指针,它负责将日志写入到 "my_log.log" 文件中。logger 是一个指向 logger 实例的共享指针,它使用上述 sink 来记录日志。通过 logger,你可以调用记录不同日志级别的方法(例如 info、warn)来记录消息。int main() {
auto sink1 = std::make_shared<spdlog::sinks::stderr_color_sink_mt>();
auto sink2 = std::make_shared<spdlog::sinks::basic_file_sink_mt>("my_log.log");
spdlog::sinks_init_list sinks = {sink1,sink2};
auto logger = std::make_shared<spdlog::logger>("my_logger", sinks.begin(),sinks.end());
logger->info("hello world ");
return 0;
}
因篇幅问题不能全部显示,请点此查看更多更全内容
Copyright © 2019- gamedaodao.net 版权所有 湘ICP备2024080961号-6
违法及侵权请联系:TEL:199 18 7713 E-MAIL:2724546146@qq.com
本站由北京市万商天勤律师事务所王兴未律师提供法律服务