日志

前言

我是一名后台程序员,接触后台只有一年时间,在这期间一共做过四个项目,分别是:

  • 工作室招新系统
  • 视频学习网站
  • 创客网站
  • 打印机项目

由于之前做项目的时候没有好好重视日志,所以导致在开发与维护项目出现了很多问题,现在分享分享我的惨痛经历:

  做第一个项目的时候,这个是我第一次开始学习后台时做的第一个项目,使用最原始的 servlet + jsp 技术,当时没有任何经验,没有把系统的需求和实现方式思考清楚就开始动工,做的过程遇到很多问题,但今天的主题不在这些问题上,而是关于日志,当时我们并没有在项目使用日志技术记录日志信息,因为该项目没有进行上线发布,所以后面做完了大部分功能之后就没继续完善和维护,所以没有意识到日志的重要性。 
  做第二个项目与第三个项目时,这是一个商业项目,由于第一次没有意识到日志的重要性,所以开发时是没有打日志的,等到项目开发完后,我们需要上线测试,部署到服务器时,发现出现了很多个 bug,但以前我们找 bug 都是通过调试或者在控制台输出错误信息来查看,部署到服务器上根本调试不了也看不到错误信息,这就导致一直找不到导致出现 bug 的地方。后面在项目添加了,但只是在 servlet 层后面添加一个全局的try catch,再记录错误信息而已,但这并没起多大作用。 
  做第四个项目时,当时有要打日志的想法,但是由于之前没做过,所以对于要如何打日志根本不理解,应该在什么地方记录日志,应该使用哪种日志级别。所以最后在项目的时候就随便乱打日志,导致最后输出的日志信息时,也是一团乱。

在基于前面的经历,觉得有必要去好好学习如何使用日志机制。

为什么要使用日志机制

  就如我之前所说的,开发以后应用服务时,如果你没有使用日志机制,那么当你将服务部署上去时,系统出 bug 了,因为没有错误信息可以查看,所以你找不到错误出现的地方,这样会不方便测试与维护。使用日志及时记录错误的信息,会更方便我们定位到错误的地方以及错误的原因,方便我们修复系统。

日志机制

日志信息级别

日志信息一般有五种级别,分别是:

  • DEBUG 
    DEBUG 级别是最低的级别,一般是为了用于测试应用程序而输出日志信息,它只能用于开发环境与测试环境,不能用于线上环境。

  • INFO 
    INFO 级别比 DEBUG 级别要高,一般用此级别来记录服务正在开启、从请求接收的信息、响应返回的信息等等

  • WARN 
    WARN 级别 比 INFO 级别要高,一般是用于记录客户端与服务端连接丢失,数据库连接丢失、Scoket 连接达到限制等一些表示 server 运行时的状态信息

  • ERROR 
    ERROR 级别 比 WARN 级别要高,一般是用于记录系统出现错误的异常错误信息,在开发时候,通过记录 ERROR 级别的信息,可以方便地定位到系统出错的地方,从而更方便地修复系统

  • FATAL 
    FATAL 级别的信息一般是用于记录非常严重的错误事件信息,该事件可能会导致应用崩溃或者停止

如何使用日志

  • 在输出 DEBUG 级别的日志信息前加一层 isDebugEnabled() 的判断,因为这是为了避免系统发布到运行环境上之后输出过多的日志信息,也避免需要为了发布而删掉或注释掉输出的 DEBUG 信息,因为这会影响日后的系统维护
  • 认真考虑好哪些信息要用哪种级别去记录日志。如果在发布环境上记录太多日志信息会影响性能,因为这会产生很多文件 IO ;但如果不记录重要的信息如接收的信息、响应的信息,将会非常困难找出错误的问题和异常在何处
  • 使用配置文件来加载日志的信息,这会方便地改变系统的日志记录级别,从而避免重启应用
  • 对于记录的日志信息,需要格式化;在高并发的系统时,需要记录当前的线程名以及当前处理类的完全限定名;记录的日志格式应一致、有用,必要的时候还要输出时间
  • 使用一系列后缀来区分不同的层次的信息。比如与数据库有关,就记录 DB_LOG,与 Session 有关,记录 SESSION_LOG,这样有利于通过后缀查找匹配出那个层次的所有日志信息,方便管理和差错
  • 如果没有为一个日志指定级别,应该让他从他的父类继承,所以我们一般通过配置文件为根日志配置级别为 DEBUG
  • 没有日志或过多的日志都是非常不好的,所以在性能和维护差错方面做好一个平衡,仔细选择要用哪些级别记录哪些信息
  • 记录的日志信息应当是简单、易懂并且对于团队来说是有效的

Log4j

为系统性能考虑,使用 Log4j 注意下列几点:

  • 避免输出 ‘%C’, ‘%f’, ‘%L’, ‘%M’ 等位置信息
  • 尽量使用异步
  • 为每个模块设置单独的输出文件
  • 每次调用前检查 if(logger.isDebugEnabled()) { logger.debug(……) }

解析:

  1. 避免输出 ‘%C’, ‘%f’, ‘%L’, ‘%M’ 等位置信息 
    当配置文件中的配置项包含 Location 信息会非常昂贵

    • %C 输出类名
    • %F 输出文件名
    • %L 输出行号
    • %M 输出函数名

注:当配置为异步输出的时候,以上位置信息可能会显示不出来,因为实在另外的一个线程记录的调用信息。此时,我们可以使用下面的方法来获取类名和函数名:

StackTraceElement se = Thread.currentThread().getStackTrace()[2];
String msg = se.getClassName() + "-[" + se.getMethodName() + "] " + errorMessage;
  1. 使用异步 
    要使用异步在于要在配置文件中配置 appender,为什么要使用异步来记录日志,前面说过记录日志信息会产生文件 IO,这会影响一定的性能,使用异步可以避免因为需要同步记录日志而产生的等待时间。

  2. 为每个模块设置单独的输出文件 
    根据模块来区分日志文件,在调试和维护某个模块时,可以更方便。

  3. 每次调用前检查 if(logger.isDebugEnabled()) { logger.debug(……) } 
    前面已说过

总结

  日志机制对于开发来说是非常重要的,它关系到调试与维护,在开发一个项目前期,应该提前部署好日志环境。同时,在开发的过程中,要想好如何去记录日志信息,要用哪种级别去记录,权衡性能与维护,选择一种较好的日志实施方案。

本文只是个人观点,如有不同意,可以说出来大家一起讨论讨论。之后再补充一篇使用 slf4j + logback 搭建日志机制的博文。

关于 logger的更多相关文章

  1. ABP源码分析八:Logger集成

    ABP使用Castle日志记录工具,并且可以使用不同的日志类库,比如:Log4Net, NLog, Serilog... 等等.对于所有的日志类库,Castle提供了一个通用的接口来实现,我们可以很方 ...

  2. org.apache.log4j.Logger详解

    org.apache.log4j.Logger 详解 1. 概述 1.1. 背景 在应用程序中添加日志记录总的来说基于三个目的 :监视代码中变量的变化情况,周期性的记录到文件中供其他应用进行统计分析工 ...

  3. Java程序日志:java.util.logging.Logger类

    一.Logger 的级别 比log4j的级别详细,全部定义在java.util.logging.Level里面.各级别按降序排列如下:SEVERE(最高值)WARNINGINFOCONFIGFINEF ...

  4. [LeetCode] Logger Rate Limiter 记录速率限制器

    Design a logger system that receive stream of messages along with its timestamps, each message shoul ...

  5. .Net Core Logger 实现log写入本地文件系统

    .net core 自带一个基础的logger框架Microsoft.Extensions.Logging. 微软默认实现了Microsoft.Extensions.Logging.Console.d ...

  6. Android源码——Logger日志系统

    Android的Logger日志系统是基于内核中的Logger日志驱动程序实现的. 日志保存在内核空间中 缓冲区保存日志   分类方法:日志的类型  +   日志的输出量   日志类型:   main ...

  7. java.lang.NoClassDefFoundError: Lorg/slf4j/Logger;

    如果你出现类似如下错误 1. Install tomcat7 in my home directory and set up `CATALINA_HOME` environment variable ...

  8. LeetCode 359 Logger Rate Limiter

    Problem: Design a logger system that receive stream of messages along with its timestamps, each mess ...

  9. 你的日志组件记录够清晰嘛?--自己开发日志组件 Logger

    现在现成的日志组件实在是太多太多,为什么我还需要自己实现呢????? 需求来源于java的log4j, [07-31 16:40:00:557:WARN : com.game.engine.threa ...

  10. log4j2 不使用配置文件,动态生成logger对象

    大家平时使用Log4j一般都是在classpath下放置一个log4j的配置文件,比如log4j.xml,里面配置好Appenders和Loggers,但是前一阵想做某需求的时候,想要的效果是每一个任 ...

随机推荐

  1. C语言编译器,写给萌新们看看。

    就我已经经历过的大学课程,仿佛每一门计算机的专业课程的开头,都是在介绍计算机发展的历史,和大名鼎鼎的冯诺依曼结构. 譬如C语言,比较水的计算机导论,c++,数据结构,计算机组成原理,甚至是Linux实 ...

  2. su

    参数选项:-,-l,--login 切换用户的同时,将用户的家目录.系统环境变量等重新按切换后的用户初始化.-c 向shell传递单个命令,仅希望在某个用户下执行命令,而不用直接切换到该用户下来操作. ...

  3. Vue收藏资料

    组件库的全局引用和按需引用:http://www.cnblogs.com/zhuanzhuanfe/p/7516745.html

  4. vs使用libevent

    1.下载最新libevent-2.1.8-stable,并解压 2.使用vs2013 工具这里使用x64,这里更新一下,改为使用x86 进入到libevent目录 运行 nmake /f Makefi ...

  5. l1 l2 loss

    衡量预测值与真实值的偏差程度的最常见的loss: 误差的L1范数和L2范数 因为L1范数在误差接近0的时候不平滑,所以比较少用到这个范数 L2范数的缺点是当存在离群点(outliers)的时候,这些点 ...

  6. __future__模块

    Python提供了__future__模块,把下一个新版本的特性导入到当前版本,于是我们就可以在当前版本中使用一些新版本的特性,比如除法: 在Python 2.x中,对于除法有两种情况,如果是整数相除 ...

  7. redis安装和简介(2)

    承接上篇未完成的配置...此次使用的的 Redis-x64-3.2.100 版本 一.打开redis服务器 方式一:打开 redis-server.exe 显示如下图: 图中: 显示运行进程号.当前运 ...

  8. FactoryBean的实现原理与作用

    FactoryBean与BeanFactory: 这俩货在拼写上很是相似,很多同学在看IOC源码或者其他地方并不能分清有啥区别,前面的IOC源码中我简单说过,现在统一简单来讲一下: FactoryBe ...

  9. AngularJS简介-起步阶段

    AngularJS 是一个为动态WEB应用设计的结构框架,提供给大家一种新的开发应用方式,这种方式可以让你扩展HTML的语法,以弥补在构建动态WEB应用时静态文本的不足,从而在web应用程序中使用HT ...

  10. Google Guava -缓存cache简单使用

    package guavacache; import java.util.concurrent.ExecutionException; import java.util.concurrent.Time ...