一文轻松理解打印有效日志

本文涉及的产品
日志服务 SLS,月写入数据量 50GB 1个月
简介: 一文轻松理解打印有效日志

引言


在日常代码测试或运行中,打印日志检测代码运行状态必不可少。先举三个例子:


在物联网系统中设备什么时候上线,可以将上线的信息写入数据库,也可以将该设备上线的记录打印到日志中,以该设备的id为文件名,查找日志也比较方便,上线时间、IP地址等打印到文本中。


在复杂的多环节系统中,快速定位问题问题出错的环节,将各个系统数据接口的数据打印日志,如果有返回值可以判断执行是否成功,可以只打印错误的日志,出现问题时查看日志文件就可以定位是那个环节。


在异常捕获中将错误的信息打印成日志文件,快速查看代码或数据出现的问题。


日志的作用


一般程序日志出自下面几个方面的需求:


记录用户操作的审计日志,甚至有的时候就是监管部门的要求。


快速定位问题的根源


追踪程序执行的过程。


追踪数据的变化


数据统计和性能分析


采集运行环境数据


一般在程序上线之后,一旦发生异常,第一件事就是要弄清楚当时发生了什么。用户当时做了什么操作,环境有无影响,数据有什么变化,是不是反复发生等,然后再进一步的确定大致是哪个方面的问题。确定是程序的问题之后再交由开发人员去重现、研究、提出解决方案。这时,日志就给我们提供了第一手的资料。


撰写日志的要求


日志的可读性


日志是给人读的,不仅仅是让自己明白,也要让没有接触过我们源代码的其他程序员也能够一目了然。有的同事在日志中打印特殊的标识符号,例如“++++++++++”, “===========”,这些符号令人眼花缭乱。另外,把日志分类输出到不同的文件也有利于我们排除干扰,迅速找到我们需要的信息。而且,最好在打印日志时输出英文,防止中文不支持而打印出乱码的情况。


日志的性能


无论我们把日志写到文件还是数据库,都需要消耗IO资源。适当的控制日志的输出也有利于提高程序的性能。例如:尽量避免在在大的循环中打印意义不大的日志内容。输出日志之前最好能判断日志的级别(例如. debug前先调用isDebugEnabled()作出判断)。


占用磁盘空间


通常,我们都是把日志写入磁盘上的日志文件中。适当的使用滚动日志并且定时清除旧文件是有好处的。我见过这样一个例子,程序运行几次后就跑不起来了,前几次都是正常的。怎么都想不明白程序有什么问题,最后才发现居然是日志文件占满了磁盘空间。在实际的应用中出现上G的日志文件也往往不少见。要在这样规模的日志文件中找出对解决问题有用的信息也是一大挑战。


日志的时效性


有的时候我们并不能及时的发现问题。需要追溯之前的日志。所以我们是需要保留一段时间以内的日志便于追溯。


日志级别


通常我们在产品环境中日志的级别都在INFO以上,所以我们必须保证在这样的情况下程序仍然能够输出足够我们作出判断的信息。


日志内容


我们在写日志的时候,需要注意输出适当的内容。首先,尽量使用业务相关的描述。我们的程序是实现某种业务的,那么就最好能描述清楚这个时候走到了业务过程的哪一步。其次,避免在日志中输出一些敏感信息,例如用户名和密码。以及,要保持编码的一致。如果不能保证就尽量使用英文而不是中文。这样当我们拿到日志之后就不会因为看到一堆乱码而不知所云了。


日志格式


常见的日志格式中对于每一条日志应含有的信息包括日期、时间、日志级别、代码位置、日志内容、错误码等信息。下面是一个工作中的日志文件的一部分内容:


代码实现

#include <iostream>
#include <afxtempl.h>     //CException
#include <ATLComTime.h>   //COleDateTime
#include <io.h>
#include <fcntl.h>
#include <stat.h>
using namespace std;
void PrintRunningLog(char *szbuff)
{
  //AfxMessageBox(szbuff);
  //打印
  int clientNumber = 1;
  CString strInfo;
  CString strCurrentTime;
  COleDateTime currentTime;
  currentTime = COleDateTime::GetCurrentTime();
  strCurrentTime=currentTime.Format("%Y-%m-%d %H:%M:%S");   //打印时间
  strInfo = strCurrentTime;
  strInfo +=" ";
  strInfo +=szbuff;
  strInfo +="\r\n";
  CString strLogTxtName;
  strLogTxtName.Format("log%d.txt",clientNumber);    //文件名
  FILE *stream;//文件流
  if ((stream = fopen(strLogTxtName,"r")) == NULL)
  {
    fopen(strLogTxtName,"w");//新建
  }
  try
  {
    int fh = _open(strLogTxtName,_O_RDWR|_O_CREAT,_S_IREAD|_S_IWRITE);
    if(fh != -1)
    {
      _lseek(fh,0L,SEEK_END);
      _write(fh,strInfo,strlen(strInfo));
      _close(fh);
    }
  }
  catch(CException *pe)   
  {
    pe->Delete();
  }
}
int main ()
{
    PrintRunningLog("test");
  return 0 ;
}


测试例子比较简单,文件名为:1


image.png


文件名称截图


测试的日志内容也比较简单,根据实际情况,更换test内容

image.png




相关实践学习
日志服务之使用Nginx模式采集日志
本文介绍如何通过日志服务控制台创建Nginx模式的Logtail配置快速采集Nginx日志并进行多维度分析。
相关文章
|
3月前
|
Java
日志框架log4j打印异常堆栈信息携带traceId,方便接口异常排查
日常项目运行日志,异常栈打印是不带traceId,导致排查问题查找异常栈很麻烦。
|
5月前
|
存储 JSON 数据格式
系统日志使用问题之为什么不要打印重复的日志,如何避免打印重复的日志
系统日志使用问题之为什么不要打印重复的日志,如何避免打印重复的日志
|
5月前
|
测试技术
系统日志使用问题之在打印业务执行日志时,需要注意哪些点
系统日志使用问题之在打印业务执行日志时,需要注意哪些点
|
4月前
|
运维 数据可视化 NoSQL
系统日志规范问题之在循环中打印INFO级别日志的反例如何解决
系统日志规范问题之在循环中打印INFO级别日志的反例如何解决
|
5月前
|
容器
打印
打印
59 0
|
移动开发
5分钟教你使用 console.log 管理你的输出日志
5分钟教你使用 console.log 管理你的输出日志
158 0
打印
4.6 打印 4.6.1 分页符的插入及删除 1、插入水平分页符 选定要插入分页符位置的下一行,在“页面布局”选项卡的“页面设置”组单击“分隔符”,在出现的下拉列表中选择”插入分页符”命令 2、插入垂直分页符 选定要插入分页符位置的右侧列,在“页面布局”选项卡的“页面设置”组单击“分隔符”,在出现的下拉列表中选择”插入分页符”命令。 3、同时插入水平、垂直分页符 选定某单元格,在“页面布局”选项卡的“页面设置”组单击“分隔符”,在出现的下拉列表中选择“插入分页符”命令此时会在该单元格左边框和上边框位置同时插入水平、垂直分页符。 4、删除手动分页符 先选择紧邻水平分页符的下面行 (或该行
|
Java
Log4j中禁止打印某一类日志
目前我们在项目中使用的日志管理大多都是 Log4j ,它确实让我们对日志的管理更加的方便,快捷
637 0
Log4j中禁止打印某一类日志
|
监控 数据库连接 数据库
说说程序中的日志
大家在写程序时,如何处理与日志相关的事宜。程序中的日志应该怎么写,以下是我的经验与分享     日志一般用于记录程序运行信息,从而使开发者方便开发调试,了解生产环境执行情况。 在我看来程序中的日志主要分为两种:异常日志和非异常日志。
882 0