服务器编程心得(五)——如何编写高性能日志

  

<强>一、服务器端日志与客户端日志的区别

  

在正式讲解之前,我们先来看一个日志类的实现方法,这个日志类也是代表着大多数客户端日志的主流写法:

  
 <代码>/* *
  * @desc:程序运行日志类,log.h
  * @author: zhangyl
  * @date: 2017.01.17
  * */的ifndef __LOG_H__
  #定义__LOG_H__
  
  # ifdef _ZYL_LOG_
  #定义LogInfo (…)日志:GetInstance ()。AddLog(“信息”,__FILE__、__LINE__ __FUNCSIG__, __VA_ARGS__)
  #定义LogWarning (…)日志:GetInstance ()。AddLog(“警告”,__FILE__、__LINE__ __FUNCSIG__, __VA_ARGS__)
  #定义LogError (…)日志:GetInstance ()。AddLog(“错误”,__FILE__、__LINE__ __FUNCSIG__, __VA_ARGS__)
  其他#
  #定义LogInfo(…)(0)(空白)
  #定义LogError(…)(0)(空白)
  # endif
  
  类日志
  {
  公众:
  静态Log&GetInstance ();
  
  bool AddLog (const char * pszLevel, const char * pszFile, int lineNo, const char * pszFuncSig, char * pszFmt,…);
  
  私人:
  日志();
  ~的日志();
  日志(const Log&);
  Log&运算符=(const Log&);
  
  私人:
  文件* m_file;
  
  };
  
  # endif//! __LOG_H__  
  
 <代码>/* *
  * @desc:程序运行日志类,log.cpp
  * @author: zhangyl
  * @date: 2017.01.17
  * */# include & lt; time.h>
  # include & lt; stdio.h>
  # include & lt; stdarg.h>
  # include“Log.h”
  
  Log&日志:GetInstance ()
  {
  静态日志日志;
  返回日志;
  }
  
  bool日志::AddLog (const char * pszLevel, const char * pszFile, int lineNo, const char * pszFuncSig, char * pszFmt,…)
  {
  如果(m_file==NULL)
  返回错误;
  
  char tmp (8192 * 10)={0};
  va_list va;//定义一个va_list型的变量,这个变量是指向参数的指针。
  va_start (va pszFmt);//用va_start宏初始化变量,这个宏的第二个参数是第一个可变参数的前一个参数,是一个固定的参数
  _vsnprintf (tmp ARRAYSIZE (tmp) pszFmt, va);//注意,不要漏掉前面的_
  va_end (va);
  
  time_t现在=(空);
  struct tm * tmstr=本地时间(和现在);
  字符内容(8192 * 10 + 256)={0};
  sprintf_s(内容、ARRAYSIZE(内容),“[% 04 d - % 2 d - % 2 d % 2 d: % 2 d: % 2 d] [% s] [0 x % 04] [% s % d % s): % s \ r \ n”,
  tmstr→tm_year + 1900,
  tmstr→tm_mon + 1,
  tmstr→tm_mday,
  tmstr→tm_hour,
  tmstr→tm_min,
  tmstr→tm_sec,
  pszLevel,
  GetCurrentThreadId (),
  pszFile,
  lineNo,
  pszFuncSig,
  tmp);
  
  如果(写入文件(内容、strlen(内容)1,m_file) !=1)
  返回错误;
  
  。fflush (m_file);
  
  返回true;
  }
  
  日志:记录()
  {
  time_t现在=(空);
  struct tm * tmstr=本地时间(和现在);
  char文件名[256];
  sprintf_s(文件名,ARRAYSIZE(文件名),“% 04 d % 2 d % 2 d % 2 d % 2 d % 02 d.runlog”,
  tmstr→tm_year + 1900,
  tmstr→tm_mon + 1,
  tmstr→tm_mday,
  tmstr→tm_hour,
  tmstr→tm_min,
  tmstr→tm_sec);
  
  m_file=fopen(文件名,“+”);
  }
  
  日志::~的日志()
  {
  如果(m_file !=NULL)
  文件关闭(m_file);
  } 
  

这个日志类的定义和实现代码节选自我的一款12306刷票软件,如果需要使用这个类的话包含Log.h头文件,然后使用宏:LogInfo/LogWarning LogError这三个宏就可以了。示例如下:

  
 <代码>字符串strResponse;
  字符串strCookie=氨?”;
  strCookie +=m_strCookies;
  如果(! HttpRequest (osURL.str () .c_str (), strResponse,真的,strCookie.c_str (), NULL,假的,10))
  {
  LogError (“QueryTickets2失败”);
  返回错误;
  } 
  

这个日志类,每次输出一行,一行中输出时间,日志级别,线程id、文件名,行号,函数签名和自定义的错误信息,演示如下:

  
 <代码>[2017-02-16 17:30:08][信息][0 x0e7c] [f: \ mycode \ hack12306 \ 12306 \ client12306演示。cpp: 1401 bool __thiscall Client12306:: HttpRequest (const char *,类std:: basic_string,类std:: allocator比;,,bool, const char *, const char *, bool, int)] http响应:{“validateMessagesShowId”:“_validatorMessage”,“状态”:真的,“httpstatus”: 200年,“数据”:{“loginAddress”:“10.1.232.219”、“otherMsg”:“”,“loginCheck”:“Y”},“消息”:[],“validateMessages”: {}}
  
  [2017-02-16 17:30:08][信息][0 x0e7c] [f: \ mycode \ hack12306 \ 12306 \ client12306演示。cpp: 1379 bool __thiscall Client12306:: HttpRequest (const char *,类std:: basic_string

服务器编程心得(五)——如何编写高性能日志