优雅的创建参数可变长的文件日志

优雅的创建参数可变长的文件日志


  最近的工作中,为发现一个bug的具体位置,需要自己手动创建一个文件日志,将原本打印在日志进程中的日志,放入一个文件当中。需要这样做的原因是由于这个bug的复现必须重启设备,但是当设备起来的时候,日志进程没抓取到有bug进程的刚启动的几个关键日志。好了废话不多说直接上代码(以C++实现)

1.日志类的实现

#pragma once
#include <string>
#include <cstdarg>
	class CFileLog
	{
	public:
		CFileLog():m_FileLocal("D:/CPP/FileLog/FileLog/log2.txt")
		{
			m_FileDesp = fopen(m_FileLocal.c_str(), "w");
			if (m_FileDesp == NULL)
			{
				printf("create file failed!\n");
			}
		}

		~CFileLog()
		{
			fclose(m_FileDesp);
		}

		static CFileLog* GetInstance()
		{
			if (m_FileLog == NULL)
			{
				m_FileLog = new CFileLog();
			}
			return m_FileLog;
		}

		void ErrLog(const char* format, ...)
		{

			char szBuf[2048] = { 0 };
			va_list arglist;
			va_start(arglist, format);
			char szBufTemp[2048] = { 0 };
#ifdef _MSC_VER 
			_vsnprintf_s(szBufTemp, 1023, format, arglist);
			sprintf_s(szBuf, "%s\r\n", szBufTemp);
#else
			vsnprintf(szBufTemp, 1023, format, arglist);
			sprintf(szBuf, "%s\r\n", szBufTemp);
#endif
			va_end(arglist);
			fprintf(m_FileDesp, "Error:%s", szBuf);
		}

		void WrnLog(const char* format, ...)
		{
			char szBuf[2048] = { 0 };
			va_list arglist;
			va_start(arglist, format);
			char szBufTemp[2048] = { 0 };
#ifdef _MSC_VER 
			_vsnprintf_s(szBufTemp, 1023, format, arglist);
			sprintf_s(szBuf, "%s\r\n", szBufTemp);
#else
			vsnprintf(szBufTemp, 1023, format, arglist);
			sprintf(szBuf, "%s\r\n", szBufTemp);
#endif
			va_end(arglist);
			fprintf(m_FileDesp, "Warning:%s", szBuf);
		}

		void InfoLog(const char* format, ...)
		{
			char szBuf[2048] = { 0 };
			va_list arglist;
			va_start(arglist, format);
			char szBufTemp[2048] = { 0 };
#ifdef _MSC_VER 
			_vsnprintf_s(szBufTemp, 1023, format, arglist);
			sprintf_s(szBuf, "%s\r\n", szBufTemp);
#else
			vsnprintf(szBufTemp, 1023, format, arglist);
			sprintf(szBuf, "%s\r\n", szBufTemp);
#endif
			va_end(arglist);
			fprintf(m_FileDesp, "Info:%s", szBuf);
		}

		void DebugLog(const char* format, ...)
		{
			char szBuf[2048] = { 0 };
			va_list arglist;
			va_start(arglist, format);
			char szBufTemp[2048] = { 0 };
#ifdef _MSC_VER 
			_vsnprintf_s(szBufTemp, 1023, format, arglist);
			sprintf_s(szBuf, "%s\r\n", szBufTemp);
#else
			vsnprintf(szBufTemp, 1023, format, arglist);
			sprintf(szBuf, "%s\r\n", szBufTemp);
#endif
			va_end(arglist);
			fprintf(m_FileDesp, "Debug:%s", szBuf);
		}
	
	public:
		static CFileLog* m_FileLog; //单例

	private:
		std::string m_FileLocal;  //文件的路径
		FILE* m_FileDesp;   //打开文件的文件描述符
	};

  在日志类中,存放私有成员变量m_FileLocal(文件的路径),m_FileDesp(文件的描述符),和类的单例。
  在成员变量中声明定义了四种日志,ErrLog(错误日志)、WrnLog(警告日志)、InfoLog(通知日志)和DebugLog(调试日志)。

2.函数参数传递的原理


  如何获取省略号指定的参数呢?在函数体内声明一个va_list,然后用va_start函数来获取参数列表的参数,使用完毕后调用va_end()结束。
  函数参数是以数据结构:栈的形式存取,从右至左入栈。首先是参数的内存存放格式:参数存放在内存的堆栈段中,在执行函数的时候,从最后一个开始入栈。因此栈底高地址,栈顶低地址,举个例子如下:
  void func(int x, float y, char z);
  那么,调用函数的时候,实参 char z 先进栈,然后是 float y,最后是 int x,因此在内存中变量的存放次序是 x->y->z,因此,从理论上说,我们只要探测到任意一个变量的地址,并且知道其他变量的类型,通过指针移位运算,则总可以顺藤摸瓜找到其他的输入变量。所以va_start使得va_list指向可变参数的第一个参数(也就是format)。   
   _vsnprintf_s的功能就是讲可变参数输出到一个字符数组中。
参数1:char *str [out],把生成的格式化的字符串存放在这里:。
参数2:size_t size [in], str可接受的最大字符数(非字节数,UNICODE一个字符两个字节),防止产生数组越界。
参数3:const char *format [in], 指定输出格式的字符串,它决定了你需要提供的可变参数的类型、个数和顺序。
参数4:va_list ap [in], va_list变量. va:variable-argument:可变参数。

所以参数会按照格式format都放入字符数组str中,在我们程序中对应的是变量szBufTemp。

3.测试日志程序

#include "Log.h"

CFileLog* CFileLog::m_FileLog = NULL;

#define LOG_WARNING(format,...)    CFileLog::GetInstance()->WrnLog(format,##__VA_ARGS__)
#define LOG_ERROR(format,...)      CFileLog::GetInstance()->ErrLog(format,##__VA_ARGS__)
#define LOG_INFO(format,...)       CFileLog::GetInstance()->InfoLog(format,##__VA_ARGS__)
#define LOG_DEBUG(format,...)      CFileLog::GetInstance()->DebugLog(format,##__VA_ARGS__)

int main()
{
	int a = 541;
	std::string wrn = "WARNINGLOG!";
	std::string err = "ERRORLOG!";
	std::string deb = "DEBUGLOG!";
	std::string info = "INFOLOG!";

	LOG_WARNING("This is test log  %s %d",wrn.c_str(), __LINE__);
	LOG_ERROR("This is test log  %s %d %d", err.c_str(), __LINE__, __LINE__);
	LOG_INFO("This is test log  %s %d %d %d", deb.c_str(), __LINE__, __LINE__, __LINE__);
	LOG_DEBUG("This is test log  %s %d %d %d %d", info.c_str(), __LINE__, __LINE__, __LINE__, __LINE__);
}

文件内输出如下图所示:

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值