217 lines
6.2 KiB
C++
217 lines
6.2 KiB
C++
#include "pch.h"
|
||
#include "aLog.h"
|
||
#include "spdlog/sinks/stdout_color_sinks.h"
|
||
#include "spdlog/sinks/basic_file_sink.h"
|
||
#include "spdlog/sinks/rotating_file_sink.h"
|
||
#include "spdlog/sinks/basic_file_sink.h"
|
||
#include "spdlog/async.h"
|
||
|
||
//app全局通用的logger实例
|
||
std::shared_ptr<spdlog::logger> alog;
|
||
|
||
static std::wstring _LogFilePath;
|
||
static std::wstring _LogFilePath2;
|
||
|
||
spdlog::sink_ptr pConsoleSink;
|
||
spdlog::sink_ptr pFileSink;
|
||
spdlog::sink_ptr pFileSink2;
|
||
|
||
// 用于console log
|
||
static FILE* _stream=nullptr;
|
||
static bool _consoleAttached = false; // 附着到父进程的控制台
|
||
static bool _consoleAllocated = false; // 我们新创建的控制台
|
||
|
||
static void _initConsoleLog()
|
||
{
|
||
// 若已存在控制台,直接使用;否则尝试附着父进程控制台,失败再创建
|
||
if (GetConsoleWindow()) {
|
||
// 已有控制台(通常是控制台子系统)
|
||
}
|
||
else if (AttachConsole(ATTACH_PARENT_PROCESS)) {
|
||
_consoleAttached = true;
|
||
}
|
||
else if (AllocConsole()) {
|
||
_consoleAllocated = true;
|
||
}
|
||
// 若成功获得控制台,重定向 stdout 并设置 UTF-8
|
||
if (GetConsoleWindow()) {
|
||
//freopen_s(&_stream, "CONOUT$", "w", stdout);
|
||
SetConsoleOutputCP(CP_UTF8);
|
||
|
||
// 尝试启用虚拟终端处理(让 ANSI 颜色也能生效,兼容使用 ansicolor sink 的场景)
|
||
HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);
|
||
if (hOut != INVALID_HANDLE_VALUE) {
|
||
DWORD mode = 0;
|
||
if (GetConsoleMode(hOut, &mode)) {
|
||
// 添加虚拟终端 & 已处理输出标志(如果父控制台支持则颜色更稳定)
|
||
SetConsoleMode(hOut, mode | ENABLE_PROCESSED_OUTPUT | ENABLE_VIRTUAL_TERMINAL_PROCESSING);
|
||
}
|
||
}
|
||
|
||
pConsoleSink = std::make_shared<spdlog::sinks::stdout_color_sink_mt>();
|
||
pConsoleSink->set_level(spdlog::level::debug);
|
||
}
|
||
}
|
||
|
||
static void _deinitConsoleLog()
|
||
{
|
||
pConsoleSink.reset();
|
||
if (_stream) {
|
||
fclose(_stream);
|
||
_stream = nullptr;
|
||
}
|
||
|
||
// 只在我们附着或创建过控制台时释放
|
||
if (_consoleAttached || _consoleAllocated) {
|
||
FreeConsole();
|
||
_consoleAttached = false;
|
||
_consoleAllocated = false;
|
||
}
|
||
}
|
||
|
||
void InitRollFileLog(std::shared_ptr<spdlog::logger>& log, const char * logname, int flag, const fs::path& logDir, const std::wstring& filename, int logfilesize_K, int logfilenum)
|
||
{
|
||
spdlog::drop(logname); // 删除原来的logger
|
||
|
||
std::time_t t = std::time(nullptr);
|
||
|
||
// 创建异步logger, 默认必须有一个文件log
|
||
|
||
auto name = fmt::format(L"{}_{:%Y%m%d_%H%M%S}.log", filename, fmt::localtime(t));
|
||
_LogFilePath = (logDir / name).wstring();
|
||
log = spdlog::create_async_nb<spdlog::sinks::rotating_file_sink_mt>(logname, _LogFilePath, size_t(logfilesize_K) * 1024, logfilenum);
|
||
|
||
|
||
pFileSink = log->sinks()[0];
|
||
|
||
// 添加console log
|
||
if (flag & INIT_CONSOLE_LOG) {
|
||
_initConsoleLog();
|
||
if(pConsoleSink) log->sinks().push_back(pConsoleSink);
|
||
}
|
||
|
||
pFileSink->set_level(spdlog::level::debug);
|
||
|
||
if(flag & INIT_ERROR_FILE_LOG) {
|
||
auto name = fmt::format(L"{}_{:%Y%m%d_%H%M%S}_error.log", filename, fmt::localtime(t));
|
||
_LogFilePath2 = (logDir / name).wstring();
|
||
pFileSink2 = std::make_shared<spdlog::sinks::rotating_file_sink_mt>(_LogFilePath2, size_t(logfilesize_K) * 1024, logfilenum);
|
||
|
||
pFileSink2->set_level(spdlog::level::warn);
|
||
log->sinks().push_back(pFileSink2);
|
||
}
|
||
|
||
log->set_level(spdlog::level::debug);
|
||
log->flush_on(spdlog::level::err); //记录error立即flush一次
|
||
spdlog::flush_every(std::chrono::seconds(5)); //5秒钟flush一次
|
||
}
|
||
|
||
void InitBasicFileLog(std::shared_ptr<spdlog::logger>& log, const char* logname, int flag, const fs::path& logDir, const std::wstring& filename)
|
||
{
|
||
spdlog::drop(logname); // 删除原来的logger
|
||
|
||
std::time_t t = std::time(nullptr);
|
||
|
||
// 创建异步logger, 默认必须有一个文件log
|
||
|
||
auto name = fmt::format(L"{}_{:%Y%m%d_%H%M%S}.log", filename, fmt::localtime(t));
|
||
_LogFilePath = (logDir / name).wstring();
|
||
log = spdlog::create_async_nb<spdlog::sinks::basic_file_sink_mt>(logname, _LogFilePath);
|
||
|
||
pFileSink = log->sinks()[0];
|
||
|
||
// 添加console log
|
||
if (flag & INIT_CONSOLE_LOG) {
|
||
_initConsoleLog();
|
||
log->sinks().push_back(pConsoleSink);
|
||
}
|
||
|
||
pFileSink->set_level(spdlog::level::debug);
|
||
|
||
if (flag & INIT_ERROR_FILE_LOG) {
|
||
auto name = fmt::format(L"{}_{:%Y%m%d_%H%M%S}_error.log", filename, fmt::localtime(t));
|
||
_LogFilePath2 = (logDir / name).wstring();
|
||
pFileSink2 = std::make_shared<spdlog::sinks::basic_file_sink_mt>(_LogFilePath2);
|
||
|
||
pFileSink2->set_level(spdlog::level::warn);
|
||
log->sinks().push_back(pFileSink2);
|
||
}
|
||
|
||
log->set_level(spdlog::level::debug);
|
||
log->flush_on(spdlog::level::err); //记录error立即flush一次
|
||
spdlog::flush_every(std::chrono::seconds(5)); //5秒钟flush一次
|
||
}
|
||
|
||
// ---- 这两段用于简单的程序,只开console log -----
|
||
|
||
// 仅开Console log
|
||
void aLogInitConsole()
|
||
{
|
||
spdlog::drop(""); // 删除默认logger
|
||
|
||
// 创建异步logger
|
||
alog = spdlog::create_async_nb<spdlog::sinks::stdout_color_sink_mt>("");
|
||
|
||
pConsoleSink = alog->sinks()[0];
|
||
pConsoleSink->set_level(spdlog::level::debug);
|
||
|
||
_initConsoleLog();
|
||
|
||
alog->set_level(spdlog::level::debug);
|
||
alog->flush_on(spdlog::level::err); //记录error立即flush一次
|
||
spdlog::flush_every(std::chrono::seconds(5)); //5秒钟flush一次
|
||
|
||
}
|
||
|
||
void LogDeinit(std::shared_ptr<spdlog::logger>& log, bool byelog)
|
||
{
|
||
// 关闭前打印一条信息
|
||
if(byelog) alog->info("Log正常关闭");
|
||
alog->flush();
|
||
Sleep(100); // 确保已经输出了
|
||
alog->sinks().clear();
|
||
|
||
if (pConsoleSink) {
|
||
_deinitConsoleLog();
|
||
}
|
||
if (pFileSink) {
|
||
pFileSink.reset();
|
||
}
|
||
if (pFileSink2) {
|
||
pFileSink.reset();
|
||
}
|
||
|
||
spdlog::shutdown();
|
||
}
|
||
|
||
// ---- 这两段用于5C,运行过程中随时开启、关闭console log -----
|
||
|
||
// 如果没开启Console log,打开
|
||
void openConsoleLog()
|
||
{
|
||
if (!pConsoleSink) {
|
||
_initConsoleLog();
|
||
}
|
||
alog->sinks().push_back(pConsoleSink);
|
||
|
||
}
|
||
|
||
// 如果已经打开了Console Log,关闭掉
|
||
void closeConsoleLog()
|
||
{
|
||
if (pConsoleSink) {//开启了console要关闭
|
||
for (auto it = alog->sinks().begin(); it != alog->sinks().end(); it++) {
|
||
if (pConsoleSink == *it) {
|
||
alog->warn("已停止刷新Log到Console");
|
||
alog->flush();
|
||
Sleep(100); // 确保已经输出了
|
||
alog->sinks().erase(it); // 假设没有别的线程在输出
|
||
Sleep(100); // 确保已经输出了
|
||
_deinitConsoleLog();
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|