Files
GdCpp12/source/aLog.cpp

217 lines
6.2 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#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;
}
}
}
}