使用boost库封装程序日志信息及崩溃日志

程序日志模块

将接口封装成函数形式,方便调用
适用于一些简单的程序

#pragma once

#include <iostream>
#include <fstream>
#include <ctime>
#include <mutex>
#include <boost/date_time.hpp>
#include <boost/filesystem.hpp>
#include "boost/format.hpp"
#include "configfile.h"    // 自定义的配置文件

using namespace boost::filesystem;

void log_Init();
void log_Info(const std::string& message);
void log_Warn(const std::string& message);
void log_Error(const std::string& message);

class Logger 
{
public:
	Logger();
	~Logger(); 

	void logInit();
	void LogInfo(const std::string& message);
	void LogWarn(const std::string& message);
	void LogError(const std::string& message);

private:
	std::string GetFileName() const;
	std::string CurrentTime() const;
	void ClearLogs();
	void Write(const std::string& message);
	bool EnableWrite();

private:
	std::ofstream file_;
	std::mutex mutex_;
	boost::gregorian::date today_;   // 今天的日期
	int keep_days;                   // 保存的天数
};
#include "Log.h"

static Logger* pLog = new Logger;

void log_Init()
{
	pLog->logInit();
}

void log_Info(const std::string& message)
{
	pLog->LogInfo(message);
}

void log_Warn(const std::string& message)
{
	pLog->LogWarn(message);
}

void log_Error(const std::string& message)
{
	pLog->LogError(message);
}

Logger::Logger()
{
	today_ = boost::gregorian::day_clock::local_day();
	keep_days = configfile::Instance()->GetSaveLogDay();
	ClearLogs();
	file_.open(GetFileName(), std::ios::app);
}

Logger::~Logger()
{
	if(file_.is_open())
		file_.close();
}

void Logger::logInit()
{
	//用于标识启动日志模块,方便查看
	Write("======================[" + CurrentTime() + "]======================\n");
}

// 打印日志信息
void Logger::LogInfo(const std::string& message)
{
	Write("[" + CurrentTime() + "] [info] " + message + "\n");
}

void Logger::LogWarn(const std::string& message)
{
	Write("[" + CurrentTime() + "] [warn] " + message + "\n");
}

void Logger::LogError(const std::string& message)
{
	Write("[" + CurrentTime() + "] [error] " + message + "\n");
}

// 获取文件名全路径
std::string Logger::GetFileName() const
{
	// 获取当前时间
	boost::posix_time::ptime time_stamp = boost::posix_time::microsec_clock::local_time();

	// 获取年月日信息
	boost::gregorian::date d = time_stamp.date();
	int year = d.year();
	int month = d.month().as_number();
	int day = d.day();

	// 将年月日时分秒拼接为字符串
	std::string name = (boost::format("%04d-%02d-%02d_") % year % month % day).str();
	name += "sea.log";

	return configfile::Instance()->GetLogPath() + "/" + name;
}

// 获取当前时间
std::string Logger::CurrentTime() const
{
	// 获取当前时间
	boost::posix_time::ptime now = boost::posix_time::microsec_clock::universal_time();

	// 格式化输出当前时间
	std::ostringstream oss;
	oss << boost::posix_time::to_iso_extended_string(now) << "."
		<< std::setfill('0') << std::setw(3)
		<< (now.time_of_day().fractional_seconds() / 1000);

	return oss.str();
}

// 清空过期日志
void Logger::ClearLogs()
{
	if(file_.is_open())
		file_.close();
	std::string path = configfile::Instance()->GetLogPath(); // 获取配置文件中的日志路径

	// 检查路径,不存在则创建
	if (path.empty())
		path = current_path().string() + "/log";
	if (!exists(path))
	{
		create_directory(path);
		return;
	}
	boost::filesystem::path folder_path(configfile::Instance()->GetLogPath());

	std::time_t current_time = std::time(nullptr);
	std::time_t max_age = keep_days * 24 * 60 * 60; // 计算日志文件最大的存储时间
	for (boost::filesystem::directory_iterator itr(folder_path); itr != boost::filesystem::directory_iterator(); ++itr)
	{
		if (boost::filesystem::is_regular_file(itr->status()))
		{
			boost::filesystem::path file_path = itr->path();
			if ("log" == file_path.extension().string())
			{
				if ((current_time - boost::filesystem::last_write_time(itr->path())) > max_age) 
				{
					boost::filesystem::remove(itr->path());
				}
			}
		}
	}
}

// 判断磁盘剩余空间
bool Logger::EnableWrite()
{
	space_info disk_space = space("/");
	if (disk_space.available < configfile::Instance()->GetMinResRoom())
		return false;
	return true;
}

// 写入日志
void Logger::Write(const std::string& message)
{
	if (!EnableWrite())
		return;
	
	// 加入互斥,防止多线程访问造成崩溃问题
	std::lock_guard<std::mutex> lock(mutex_);
	if (!file_.is_open())
	{
		file_.open(GetFileName(), std::ios::app);
		if (!file_.is_open())
			return;
	}

	try 
	{
		file_.write(message.c_str(), message.size());
		file_.close();
	}
	catch (std::exception &e)
	{
		std::cerr << "log error:" << e.what()<<std::endl;
	}
	
	boost::gregorian::date today = boost::gregorian::day_clock::local_day();
	if (today != today_)
	{
		ClearLogs();
		today_ = today;
	}
}

崩溃日志模块

主要通过调用windows接口实现对崩溃信息的抓取
发生崩溃时会在当前路径下创建dump文件夹,在该文件夹下生成一个.dmp文件,再使用visual studio打开,查看崩溃信息

#pragma once 

#include <windows.h>
#include <iostream>
#include <string>
#include <locale>
#include <codecvt>
#include <boost/filesystem.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>

namespace ysm {

	class Debug
	{
	public:
		static LONG WINAPI  crashStackCallback(struct _EXCEPTION_POINTERS* exceptionInfo);
	};
}
#include "Debug.h"
#include <Dbghelp.h>
#pragma comment(lib, "Dbghelp.lib")

namespace ysm
{
	LONG WINAPI Debug::crashStackCallback(struct _EXCEPTION_POINTERS* exceptionInfo)
	{
		std::string savePath = boost::filesystem::current_path().string() + "/dump/";
		if (!boost::filesystem::exists(savePath))
		{
			if (!boost::filesystem::create_directory(savePath))
				return EXCEPTION_EXECUTE_HANDLER;
		}

		
		boost::posix_time::ptime time_local = boost::posix_time::second_clock::local_time();
		std::string time_str = boost::posix_time::to_simple_string(time_local);
		time_str = boost::replace_all_copy(time_str, " ", "-"); // 将空格替换为 "-"
		time_str = boost::replace_all_copy(time_str, ":", "_"); // 将冒号替换为 "_"
		time_str = time_str.substr(0, time_str.length() - 2); // 去掉秒的小数部分
		savePath.append("crash_");
		savePath.append(time_str);
		int id = GetCurrentThreadId();
		savePath.append(std::to_string(id));
		savePath.append(".dmp");

		std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> converter;
		std::wstring wstr = converter.from_bytes(savePath);
		HANDLE dump = CreateFileW(wstr.c_str(),
			GENERIC_WRITE,
			0,
			NULL,
			CREATE_ALWAYS,
			FILE_ATTRIBUTE_NORMAL, NULL);
		if (INVALID_HANDLE_VALUE == dump)
		{
			//app->exit(E_UNEXPECTED);
			return EXCEPTION_EXECUTE_HANDLER;
		}

		MINIDUMP_EXCEPTION_INFORMATION miniDumpExceptionInfo;
		miniDumpExceptionInfo.ExceptionPointers = exceptionInfo;
		miniDumpExceptionInfo.ThreadId = GetCurrentThreadId();
		miniDumpExceptionInfo.ClientPointers = TRUE;
		DWORD idProcess = GetCurrentProcessId();
		MiniDumpWriteDump(GetCurrentProcess(),
			idProcess,
			dump,
			MiniDumpWithFullMemory, &miniDumpExceptionInfo, NULL, NULL);

		// 第四个参数 DumpType 指定类型,用于生成包含不同信息、大小的dump日志。
		CloseHandle(dump);

		//app->exit(E_UNEXPECTED);
		return EXCEPTION_EXECUTE_HANDLER;
	}
}

一般在主程序中启用

SetUnhandledExceptionFilter(ysm::Debug::crashStackCallback);
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值