java日志使用

您所在的位置:网站首页 java系统开发项目日志 java日志使用

java日志使用

2024-07-11 10:38| 来源: 网络整理| 查看: 265

java日志:日志就是记录程序的运行轨迹,方便查找关键信息,也方便快速定位解决问题。

常用的日志框架:Log4j 、Slf4j 、Logback 。

在JDK 1.3及以前,Java打日志依赖System.out.println(), System.err.println()或者e.printStackTrace(),Debug日志被写到STDOUT流,错误日志被写到STDERR流。这样打日志有一个非常大的缺陷,即无法定制化,且日志粒度不够细。于是, Gülcü 于2001年发布了Log4j,后来成为Apache 基金会的顶级项目。Log4j 在设计上非常优秀,对后续的 Java Log 框架有长久而深远的影响,它定义的Logger、Appender、Level等概念如今已经被广泛使用。Log4j 的短板在于性能,在Logback 和 Log4j2 出来之后,Log4j的使用也减少了。

Slf4j 也是现在主流的日志门面框架,使用 Slf4j 可以很灵活的使用占位符进行参数占位,简化代码,拥有更好的可读性。

Logback 是 Slf4j 的原生实现框架,同样也是出自 Log4j 一个人之手,但拥有比 log4j 更多的优点、特性和更做强的性能,现在基本都用来代替 log4j 成为主流。

日志级别

日志级别详解 日志级别描述OFF关闭:最高级别,不输出日志。FATAL致命:输出非常严重的可能会导致应用程序终止的错误。ERROR错误:输出错误,但应用还能继续运行。WARN警告:输出可能潜在的危险状况。INFO信息:输出应用运行过程的详细信息。DEBUG调试:输出更细致的对调试应用有用的信息。TRACE跟踪:输出更细致的程序运行轨迹。ALL所有:输出所有级别信息。

 

日志优先级别标准顺序为:ALL < TRACE < DEBUG < INFO < WARN < ERROR < FATAL < OFF

什么时候打日志:

当你遇到问题的时候,只能通过debug功能来确定问题,你应该考虑打日志,良好的系统,是可以通过日志进行问题定为的。当你碰到if…else 或者 switch这样的分支时,要在分支的首行打印日志,用来确定进入了哪个分支经常以功能为核心进行开发,你应该在提交代码前,可以确定通过日志可以看到整个流程

项目开发中打日志的基本格式:

   正确的姿势

 logger.debug("Processing trade with param1:[{}] and param2: [{}] ", param1, param2); 

   不推荐的姿势:这种会进行字符串的拼接,产生很多String对象,占用空间,影响性能。

logger.debug("Processing trade with param1: " + param1 + " param2: " + param2);

  

public PayResponse create(OrderDTO orderDTO) { PayRequest payRequest = new PayRequest(); payRequest.setOpenid(orderDTO.getBuyerOpenid()); payRequest.setOrderAmount(orderDTO.getOrderAmount().doubleValue()); payRequest.setOrderId(orderDTO.getOrderId()); payRequest.setOrderName(ORDER_NAME); payRequest.setPayTypeEnum(BestPayTypeEnum.WXPAY_H5); log.info("【微信支付】发起支付, request={}", JsonUtil.toJson(payRequest)); PayResponse payResponse = bestPayService.pay(payRequest); log.info("【微信支付】发起支付, response={}", JsonUtil.toJson(payResponse)); return payResponse; }

 

日志配置文件:log4j.properties文件或者logback.xml。

  log4j.properties文件

###配置日志根Logger log4j.rootLogger=DEBUG,stdout,D,E,I,file #ERROR 为严重错误 主要是程序的错误 #WARN 为一般警告,比如session丢失 #INFO 为一般要显示的信息,比如登录登出 #DEBUG 为程序的调试信息 log4j.additivity.org.apache=true ###配置日志信息输出目的地Appender log4j.appender.stdout=org.apache.log4j.ConsoleAppender ### 输出到日志文件 ### #org.apache.log4j.ConsoleAppender(控制台) #org.apache.log4j.FileAppender(文件) #org.apache.log4j.DailyRollingFileAppender(每天产生一个日志文件) #org.apache.log4j.RollingFileAppender(文件大小到达指定尺寸的时候产生一个新的文件) #org.apache.log4j.WriterAppender(将日志信息以流格式发送到任意指定的地方) #log4j.appender.error.Target=System.out log4j.appender.D = org.apache.log4j.DailyRollingFileAppender log4j.appender.D.File = /data/log/bill.debug.log log4j.appender.file.layout=org.apache.log4j.PatternLayout log4j.appender.file.DatePattern='.'yyyy-MM-dd-HH-mm # '.'yyyy-MM:每月 # '.'yyyy-ww:每周 # '.'yyyy-MM-dd:每天 # '.'yyyy-MM-dd-a:每天两次 # '.'yyyy-MM-dd-HH:每小时 # '.'yyyy-MM-dd-HH-mm:每分钟 #log4j.appender.file.MaxFileSize=1MB ###滚动文件的最大数 #log4j.appender.file.MaxBackupIndex=8 log4j.appender.file.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} [%-5p](%-30c{1}) [TxId : %X{PtxId} , SpanId : %X{PspanId}] [ET:%X{ENV_TYPE},AN:%X{APP_NAME},SN:%X{SERVICE_NAME},CN:%X{CONTAINER_NAME},CI:%X{CONTAINER_IP}] %m%n log4j.appender.file.Threshold=DEBUG ###将消息增加到指定文件中,false指将消息覆盖指定的文件内容 log4j.appender.file.append=true ###日志的保存位置 #log4j.appender.file.File=E:/logs/file-debug-log.log log4j.appender.file.File=E:/logs/debug-debug.log ###每天产生一个日志文件 #log4j.appender.file=org.apache.log4j.DailyRollingFileAppender #log4j.appender.file.layout=org.apache.log4j.PatternLayout #log4j.appender.file.maxFileSize=100 #log4j.appender.file.maxBackupIndex=5 #log4j.appender.file.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} [%-5p](%-30c{1}) [TxId : %X{PtxId} , SpanId : %X{PspanId}] [ET:%X{ENV_TYPE},AN:%X{APP_NAME},SN:%X{SERVICE_NAME},CN:%X{CONTAINER_NAME},CI:%X{CONTAINER_IP}] %m%n #log4j.appender.file.Threshold=DEBUG #log4j.appender.file.append=true #log4j.appender.file.File=E:/logs/debug-log.log log4j.appender.D.Append = true log4j.appender.D.Threshold = DEBUG ###配置日志信息的格式(布局) log4j.appender.stdout.layout=org.apache.log4j.PatternLayout #org.apache.log4j.HTMLLayout(以HTML表格形式布局) #org.apache.log4j.PatternLayout(可以灵活地指定布局模式) #org.apache.log4j.SimpleLayout(包含日志信息的级别和信息字符串) #org.apache.log4j.TTCCLayout(包含日志产生的时间、线程、类别等等信息) log4j.appender.D.layout = org.apache.log4j.PatternLayout ###配置日志打印的格式格式化日志信息 #%m 输出代码中指定的消息 #%p 输出优先级,即DEBUG,INFO,WARN,ERROR,FATAL #%r 输出自应用启动到输出该log信息耗费的毫秒数 #%c 输出所属的类目,通常就是所在类的全名 #%t 输出产生该日志事件的线程名 #%n 输出一个回车换行符,Windows平台为“\r\n”,Unix平台为“\n” #%d 输出日志时间点的日期或时间,默认格式为ISO8601,也可以在其后指定格式,比如:%d{yyy MMM dd HH:mm:ss , SSS} #%l 输出日志事件的发生位置,包括类目名、发生的线程,以及在代码中的行数 log4j.appender.D.layout.ConversionPattern = %-d{yyyy-MM-dd HH:mm:ss} [%t:%r] - [%p] %m%n ### 输出到日志文件 ### log4j.appender.I = org.apache.log4j.DailyRollingFileAppender log4j.appender.I.File = /data/log/bill.info.log log4j.appender.I.Append = true log4j.appender.I.Threshold = INFO log4j.appender.I.layout = org.apache.log4j.PatternLayout log4j.appender.I.layout.ConversionPattern = %-d{yyyy-MM-dd HH:mm:ss} [%t:%r] - [%p] %m%n ### 保存异常信息到单独文件 ### log4j.appender.E = org.apache.log4j.DailyRollingFileAppender log4j.appender.E.File = /data/log/bill.error.log log4j.appender.E.Append = true log4j.appender.E.Threshold = ERROR log4j.appender.E.layout = org.apache.log4j.PatternLayout log4j.appender.E.layout.ConversionPattern =%-d{yyyy-MM-dd HH:mm:ss} [%t:%r] - [%p] %m%

       

 logback.xml

%d{yyyy-M-d HH:mm:ss} %t %p %m%n logs/logback/springboot_%d{yyyy-M-d}.log 10 %d{yyyy-M-d HH:mm:ss} %t %p %m%n UTF-8 logs/logback/faw_tsp_basicinfo_%d{yyyy-M-d}.log 100 %d{yyyy-M-d HH:mm:ss} %t %p %m%n

 springboot已经集成了slf4j

几个错误的打日志方式:

 

1. 不要使用 System.out.print..

输出日志的时候只能通过日志框架来输出日志,而不能使用 System.out.print.. 来打印日志,这个只会打印到 tomcat 控制台,而不会记录到日志文件中,不方便管理日志,如果通过服务形式启动把日志丢弃了那更是找不到日志了。

2. 不要使用 e.printStackTrace()

首先来看看它的源码:

public void printStackTrace() { printStackTrace(System.err); }

它其实也是利用 System.err 输出到了 tomcat 控制台。

3. 不要抛出异常后又输出日志

如捕获异常后又抛出了自定义业务异常,此时无需记录错误日志,由最终捕获方进行异常处理。不能又抛出异常,又打印错误日志,不然会造成重复输出日志。

try { // ... } catch (Exception e) { // 错误 LOG.error("xxx", e); throw new RuntimeException(); }

4. 不要使用具体的日志实现类

InterfaceImpl interface = new InterfaceImpl();

这段代码大家都看得懂吧?应该面向接口的对象编程,而不是面向实现,这也是软件设计模式的原则,正确的做法应该是。

Interface interface = new InterfaceImpl();

日志框架里面也是如此,上面也说了,日志有门面接口,有具体实现的实现框架,所以大家不要面向实现编程。

5. 没有输出全部错误信息

看以下代码,这样不会记录详细的堆栈异常信息,只会记录错误基本描述信息,不利于排查问题。

try { // ... } catch (Exception e) { // 错误 LOG.error('XX 发生异常', e.getMessage()); // 正确 LOG.error('XX 发生异常', e); }

6. 不要使用错误的日志级别

曾经在线上定位一个问题,同事自信地和我说:明明输出了日志啊,为什么找不到...,后来我去看了下他的代码,是这样的:

try { // ... } catch (Exception e) { // 错误 LOG.info("XX 发生异常...", e); }

大家看出了什么问题吗?用 info 记录 error 日志,日志输出到了 info 日志文件中了,同事拼命地在 error 错误日志文件里面找怎么能找到呢?

7. 不要在千层循环中打印日志

这个是什么意思,如果你的框架使用了性能不高的 Log4j 框架,那就不要在上千个 for循环中打印日志,这样可能会拖垮你的应用程序,如果你的程序响应时间变慢,那要考虑是不是日志打印的过多了。

for(int i=0; i


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3