1、log4j已成为大型系统必不可少的一部分,log4j可以很方便的帮助我们在程序的任何位置输出所要打印的信息,便于我们对系统在调试阶段和正式运行阶段对问题分析和定位。由于日志级别的不同,对系统的性能影响也是有很大的差距,日志级别越高,性能越高。

2、log4j主要分为error,warn,info,debug四个级别,也是使用最多的四种,日志级别从左至右依次增加。

3、log4j对系统性能的影响程度主要体现在以下几方面:    
   a、日志输出的目的地,输出到控制台的速度比输出到文件系统的速度要慢。 
   b、日志输出格式不一样对性能也会有影响,如简单输出布局(SimpleLayout)比格式化输出布局(PatternLayout)输出速度要快。可以根据需要尽量采用简单输出布局格式输出日志信息。 
   c、日志级别越低输出的日志内容就越多,对系统系能影响很大。 
   d、日志输出方式的不同,对系统系能也是有一定影响的,采用异步输出方式比同步输出方式性能要高。 
   e、每次接收到日志输出事件就打印一条日志内容比当日志内容达到一定大小时打印系能要低。

4、针对以上几点对系能的影响中的第4,5点,对日志配置文件做如下配置: 
    a、设置日志缓存,以及缓存大小

Java代码  
  1. log4j.appender.A3.BufferedIO=true
  2. #Buffer单位为字节,默认是8K,IO BLOCK大小默认也是8K
  3. log4j.appender.A3.BufferSize=8192

以上配置说明,当日志内容达到8k时,才会将日志输出到日志输出目的地。 
  
b、设置日志输出为异步方式

Java代码  
  1. <appender name="DRFOUT" class="org.apache.log4j.DailyRollingFileAppender">
  2. <param name="File" value="logs/brws.log" />
  3. <param name="Append" value="true" />
  4. <param name="DatePattern" value="yyyy_MM_dd'.'" />
  5. <layout class="org.apache.log4j.PatternLayout">
  6. <param name="ConversionPattern" value="%d [%t] %-5p %l %x - %m%n" />
  7. </layout>
  8. </appender>
  9. <appender name="ASYNCOUT" class="org.apache.log4j.AsyncAppender">
  10. <param name="BufferSize" value="512" />
  11. <appender-ref ref="DRFOUT" />
  12. </appender>

同步情况: 各线程直接获得输出流进行输出(线程间不需要同步)。 
异步情况: 1.各线程将日志写到缓存,继续执行下面的任务(这里是异步的) 
          
2.日志线程发现需要记日志时独占缓存(与此同时各线程等待,此时各线程是被阻塞住的),从缓存中取出日志信息,获得输出流进行输出,将缓存解锁(各线程收到提醒,可以接着写日志了)

众所周知,磁盘IO操作、网络IO操作、JDBC操作等都是非常耗时的,日志输出的主要性能瓶颈也就是在写文件、写网络、写JDBC的时候。日志是肯定要记的,而要采用异步方式记,也就只有将这些耗时操作从主线程当中分离出去才真正的实现性能提升,也只有在线程间同步开销小于耗时操作时使用异步方式才真正有效 !

现在我们接着分别来看看这几种记录日志的方式:

a、将日志记录到本地文件 同样都是写本地文件Log4j本身有一个buffer处理入库,采用异步方式并不一定能提高性能(主要是如何配置好缓存大小);而线程间的同步开销则是非常大的!因此在使用本地文件记录日志时不建议使用异步方式。     
     b、将日志记录到JMS JMS本身是支持异步消息的,如果不考虑JMS消息创建的开销,也不建议使用异步方式。     
    c、将日子记录到SOCKET 将日志通过Socket发送,纯网络IO操作不需要反馈,因此也不会耗时  
     d、将日志记录到数据库 众所周知JDBC是几种方式中最耗时的:网络、磁盘、数据库事务,都使JDBC操作异常的耗时,在这里采用异步方式入库倒是一个不错的选择。     
    e、将日志记录到SMTP 同JDBC

5、异步输出日志工作原理    
   AsyncAppender采用的是生产者消费者的模型进行异步地将Logging Event送到对应的Appender中。

a、 生产者:外部应用了Log4j的系统的实时线程,实时将Logging Event传送进AsyncAppender里

b、 中转:Buffer和DiscardSummary

c、 消费者:Dispatcher线程和appenders  
工作原理:

1) Logging Event进入AsyncAppender,AsyncAppender会调用append方法,在append方法中会去把logging Event填入Buffer中,当消费能力不如生产能力时,AsyncAppender会把超出Buffer容量的Logging Event放到DiscardSummary中,作为消费速度一旦跟不上生成速度,中转buffer的溢出处理的一种方案。

2)  AsyncAppender有个线程类Dispatcher,它是一个简单的线程类,实现了Runnable接口。它是AsyncAppender的后台线程。

Dispatcher所要做的工作是:

① 锁定Buffer,让其他要对Buffer进行操作的线程阻塞。

② 看Buffer的容量是否满了,如果满了就将Buffer中的Logging Event全部取出,并清空Buffer和DiscardSummary;如果没满则等待Buffer填满Logging Event,然后notify Disaptcher线程。

③ 将取出的所有Logging Event交给对应appender进行后面的日志信息推送。

以上是AsyncAppender类的两个关键点:append方法和Dispatcher类,通过这两个关键点实现了异步推送日志信息的功能,这样如果大量的Logging Event进入AsyncAppender,就可以游刃有余地处理这些日志信息了。

************************************************************************************************************************************************************************

************************************************************************************************************************************************************************

不久前在系统中完成了监控的功能,监控系统的信息量很大,用户对页面的每一个点击都会产生记录,每天下来的日志量有2G多,我用log4j把这些监控记录 放在日志里,然后进行异步处理,但即使是这样,记录日志会对磁盘IO产生频繁的访问,而IO通常就是系统的瓶颈所在。于是对log4j配置进行一些调优就 成了必要。下面是我系统中的log4j配置:

log4j.rootLogger=ERROR,fileout,stdout
log4j.logger.monitorLogger=INFO,monitorAppenderlog4j.additivity.monitorLogger=falselog4j.appender.stdout=org.apache.log4j.ConsoleAppenderlog4j.appender.stdout.layout=org.apache.log4j.PatternLayoutlog4j.appender.stdout.layout.ConversionPattern=%d (%F:%L) %-5p %c - %m%nlog4j.appender.fileout=org.apache.log4j.DailyRollingFileAppenderlog4j.appender.fileout.File=logs/server_log.txtlog4j.appender.fileout.layout=org.apache.log4j.PatternLayoutlog4j.appender.fileout.layout.ConversionPattern=%d [%t] (%F:%L) %-5p %c - %m%nlog4j.appender.monitorAppender=org.apache.log4j.DailyRollingFileAppenderlog4j.appender.monitorAppender.File=mtlogs/mt_log.txtlog4j.appender.monitorAppender.layout=org.apache.log4j.PatternLayoutlog4j.appender.monitorAppender.layout.ConversionPattern=%m%nlog4j.appender.monitorAppender.DatePattern='.'yyyy-MM-dd-HHlog4j.appender.monitorAppender.BufferedIO=true#Buffer单位为字节,默认是8K
log4j.appender.monitorAppender.BufferSize=8192

1) log4j.additivity.monitorLogger=false
这个选项用于控制监控logger的日志不会输出到rootlogger,否则无论会产生许多重复的数据,同时也会影响性能;

2) log4j.appender.monitorAppender.DatePattern='.'yyyy-MM-dd-HH
这个选项用于告诉 DailyRollingFileAppender每小时输出日志,而不是默认的一天输出一次,因为监控日志的数据量很巨大,如果以天为单位输出,日志文件会很大(G级),而且再处理会很耗时。
其他一些输出选项还有:
1)'.'yyyy-MM: 每月 
2)'.'yyyy-ww: 每周 
3)'.'yyyy-MM-dd: 每天 
4)'.'yyyy-MM-dd-a: 每天两次 
5)'.'yyyy-MM-dd-HH: 每小时 
6)'.'yyyy-MM-dd-HH-mm: 每分钟

3) log4j.appender.monitorAppender.BufferedIO=true
log4j.appender.monitorAppender.BufferSize=8192
这 个选项用于告诉log4j输出日志的时候采用缓冲的方式,而不是即时flush方式,并且设定了缓冲为8K,8K是默认值,可以根据日志输出的情况来修 改。这个选项很重要,在测试中发现,当并发访问很高,例如每一秒100个并发以上,使用缓存跟不使用缓冲差距很大。具体数字我这里就不列出来了。
另外我想说的是,log4j输出缓冲日志是以8K为单位的,因为磁盘的一个block为8K,这样可以减少碎片,也就是说假设你设置缓存为18K,log4j在16K(8K*2)的时候就会输出),而不是18K。

4)组装输出内容之前可对logger的输出级别先进行判断而不要完全依赖log4j控制,因为组装输出日志内容也是要损耗效率的。
        //若log4j并未开启info级日志记录,直接返回
        if(!monitorLogger.isInfoEnabled()){
            return;
        }
        StringBuilder log = new StringBuilder();
        logSql.append(logPk+" ");
        ...

5)使用异步输出 org.apache.log4j.AsyncAppender,异步输出必须使用xml方式配置才能支持,我把上面properties形式的配置文件用xml表达一下:

<?xml version="1.0" encoding="UTF-8"?>
<log4j:configuration debug="true"><appender name="stdout"class="org.apache.log4j.ConsoleAppender"><layout class="org.apache.log4j.PatternLayout"><param name="ConversionPattern" value="%d (%F:%L) %-5p %c - %m%n" /></layout></appender><appender name="fileout"class="org.apache.log4j.DailyRollingFileAppender"><layout class="org.apache.log4j.PatternLayout"><param name="ConversionPattern" value="%d [%t] (%F:%L) %-5p %c - %m%n" /></layout><param name="File"value="logs/server_log.txt" /></appender><appender name="monitorAppender"class="org.apache.log4j.DailyRollingFileAppender"><layout class="org.apache.log4j.PatternLayout"><param name="ConversionPattern" value="%m%n" /></layout><param name="DatePattern" value="'.'yyyy-MM-dd-HH" />        <param name="File" value="mtlogs/mt_log.txt" /><param name="BufferedIO" value="true" /><!-- 8K为一个写单元 --><param name="BufferSize" value="8192" /></appender><appender name="async" class="org.apache.log4j.AsyncAppender"><appender-ref ref="monitorAppender"/></appender><root><priority value="error" /><appender-ref ref="stdout" /><appender-ref ref="fileout" /></root><category name="com.danga.MemCached"><priority value="error" /><appender-ref ref="fileout" /></category ><category name="com.opensymphony"><priority value="error" /><appender-ref ref="fileout" /></category ><category name="monitorLogger" additivity="false"><priority value="info" /><appender-ref ref="async" /></category >
</log4j:configuration>

【2】log4j 格式详解

 log4j.rootLogger=日志级别,appender1, appender2, ….

  • 日志级别:ALL<DEBUG<INFO<WARN<ERROR<FATAL<OFF,不区分大小写
  • 注意,需在控制台输入,只需将其中一个appender定义为stdout即可
  • 注意,rootLogger默认是对整个工程生效
  • 注意,如果只想对某些包操作,那么:log4j.logger.com.hutu=info, stdout,表示该日志对package com.hutu生效
  • 注意,这样做可以区分dev/线上,也可以减小性能影响:if(log.isDebugEnabled()){log.debug();}

 log4j.appender.appender1=org.apache.log4j.日志输出到哪儿

  • ConsoleAppender(控制台)
  • FileAppender(文件)
  • DailyRollingFileAppender(每天产生一个日志文件)
  • RollingFileAppender(文件大小到达指定尺寸时产生一个新的文件)
  • WriteAppender(将日志信息以流格式发送到任意指定的地方)
  • JDBCAppender(将日志信息保存到数据库中)

 log4j.appender.appender1.File=文件目录及文件

${user.home}/logs/...

 log4j.appender.appender1.MaxFileSize=最大文件大小

 log4j.appender.appender1.MaxBackupIndex=备份文件个数

  • 其中,appender1是在第一行定义过的;
  • 文件目录及文件,例如,/home/admin/logs/hutudan.log
  • 最大文件大小,例如,100KB
  • 备份文件个数,例如,1

 log4j.appender.ServerDailyRollingFile.DatePattern=日志后缀格式

  • 例如,'.'yyyy-MM-dd

 log4j.appender.appender1.layout=org.apache.log4j.日志布局格式

  • HTMLLayout(以HTML表格形式布局)
  • SimpleLayout(包含日志信息的级别和信息字符串)
  • TTCCLayout(包含日志产生的时间,执行绪,类别等信息)
  • PatternLayout(可以灵活的指定布局格式,常用)

 log4j.appender.appender1.layout.ConversionPattern=日志输出格式

  1. 例如,%d - %m%n或%d{yyyy-MM-dd HH:mm:ss} %p [%c] %m%n
  2. %c 输出日志信息所属的类的全名
  3. %d 输出日志时间点的日期或时间,默认格式为ISO8601,也可以在其后指定格式,比如:%d{yyy-M-dd HH:mm:ss },输出类似:2002-10-18- 22:10:28
  4. %f 输出日志信息所属的类的类名
  5. %l 输出日志事件的发生位置,即输出日志信息的语句处于它所在的类的第几行
  6. %m 输出代码中指定的信息,如log(message)中的message
  7. %n 输出一个回车换行符,Windows平台为“rn”,Unix平台为“n”
  8. %p 输出优先级,即DEBUG,INFO,WARN,ERROR,FATAL。如果是调用debug()输出的,则为DEBUG,依此类推
  9. %r 输出自应用启动到输出该日志信息所耗费的毫秒数
  10. %t 输出产生该日志事件的线程名
  11. 可参考:http://blog.sina.com.cn/s/blog_4e4dd5570100qowy.html

 log4j.appender.ServerDailyRollingFile.Append=true

  • 例如,不解释,追加往后写便是

 总结一下:

  • Logger类:完成日志记录,设置日志信息级别
  • Appender类:决定日志去向,终端、DB、硬盘
  • Layout类:决定日志输出的样式,例如包含当前线程、行号、时间

log4j日志输出性能优化-缓存、异步相关推荐

  1. log4j日志输出性能优化

    1.log4j已成为大型系统必不可少的一部分,log4j可以很方便的帮助我们在程序的任何位置输出所要打印的信息,便于我们对系统在调试阶段和正式运行阶段对问题分析和定位.由于日志级别的不同,对系统的性能 ...

  2. Mybatis 的Log4j日志输出问题 - 以及有关日志的所有问题

    转载自   Mybatis 的Log4j日志输出问题 - 以及有关日志的所有问题 使用Mybatis的时候,有些时候能输出(主要是指sql,参数,结果)日志.有些时候就不能. 无法输出日志的时候,无论 ...

  3. API性能优化之异步

    很多时候为了达到SLA承诺(Service-Level Agreement)即为"服务水平承诺,我们需要拼命的优化我们的api的性能,其中最有效的便是异步了 异步和同步: 定义:同步和异步关 ...

  4. mysql数据库前端缓存_MySQL数据库性能优化--缓存参数优化

    在平时被问及最多的问题就是关于 MySQL 数据库性能优化方面的问题,所以最近打算写一个MySQL数据库性能优化方面的系列文章,希望对初中级 MySQL DBA 以及其他对 MySQL 性能优化感兴趣 ...

  5. 《深入浅出DPDK》读书笔记(八):网卡性能优化(异步中断模式、轮询模式、混和中断轮询模式)

    本文内容为读书笔记,摘自<深入浅出DPDK> 82.DPDK的轮询模式 <DPDK PMD( Poll Mode Driver)轮询模式驱动程序> DPDK采用了轮询或者轮询混 ...

  6. Log4j日志输出详细

    日志论 在应用程序中输出日志有有三个目的: (1 )监视代码中变量的变化情况,把数据周期性地记录到文件中供其他应用进行统计分析工作. (2 )跟踪代码运行进轨迹,作为日后审计的依据. (3 )担当集成 ...

  7. iOS tableView性能优化之异步排版和绘制渲染----YYText框架学习(YYTextAsyncLayer)

    YYWebImage源码分析 YYImage源码 YYModel源码解析 前言 这段时间针对设计架构,解耦以及性能优化相关的知识点看了不少,前两者可以看MVVM和AOP编程思路,最后一个是昨天看的,Y ...

  8. 网页性能优化之异步加载js文件

    一个网页的有很多地方可以进行性能优化,比较常见的一种方式就是异步加载js脚本文件.在谈异步加载之前,先来看看浏览器加载js文件的原理. 浏览器加载 JavaScript 脚本,主要通过<scri ...

  9. log4j日志输出框架

    什么是log4j框架呢? log4j是一个日志输出框架,用于输出日志的.比如MyBatis的日志就是通过log4j输出的,主流框架都是log4j输出的,Spring框架 也可以通过log4j输出日志! ...

最新文章

  1. mysql语句生成工具_强烈推荐一款MySQL语句优化辅助工具,值得收藏
  2. 徐博 From RankNet to LambdaRank to LambdaMART: An Overview
  3. php mysql query 创建_借助PHP的mysql_query()函数来创建MySQL数据库的教程_MySQL
  4. fofa自动化爬虫脚本更新+详解
  5. 第十七届“科大讯飞杯”高校网络友谊赛——F-排列计算
  6. tab切换webuploader失效的解决方法
  7. mapgis安装|计算机中丢失basroot.dll
  8. onkeyup事件只能输入数字,字母,下划线等
  9. 1.3亿元战略投资落地,有赞的盈利拐点到了吗?
  10. KANZI-01-安装
  11. 一日一技|Stata筛选出字符串中非数字的行
  12. Facebook的普惠金融数字货币Libra
  13. htc 8x android,htc8x怎么样 htc8x测评【图解】
  14. 什么是分库分表?为什么需要分表?什么时候分库分表
  15. 贮藏 git stash
  16. 智能机房动力环境集中监控管理系统
  17. 【Excel 函数】Office 365 之Excel函数之Right
  18. Mysql基础-------初识数据库,三大范式
  19. 导数 与 偏导数的推导
  20. Android游戏开发之游戏帧动画的播放与处理(七)

热门文章

  1. 嵌入式Linux驱动学习【9】—— Nor Flash
  2. 机械手臂c语言如何编程,一种串联机械手臂的示教编程方法
  3. 解决报错npm ERR request to https://registry.cnpmjs.org/wangeditor failed, reason: Hostname/
  4. 严重: Servlet [login_fali] in web application [/StudyforJSP] threw load() exception javax.servl
  5. 学渣的刷题之旅 leetcode刷题 7.整数反转
  6. 5G通信基础知识学习
  7. CentOS 7下配置hadoop 2.8 分布式集群
  8. 牛顿法及其下山法+C代码
  9. android app自动拍照6,6款手机拍照处理软件,大片生成,值得点赞收藏,不快来看一下?...
  10. 安卓转战React-Native之签名打包成Apk并极速多渠道打包