精华内容
下载资源
问答
  • 多进程log4j日志丢失问题分析

    千次阅读 2018-07-03 11:06:20
    一、背景:后台有很任务,每个任务都是一个main函数(JVM或进程),但是所有的任务都加载同一个log4j.xml文件,即往同一份文件中输出日志。二、原因追踪:在 log4j 的 DailyRollingFileAppender 类中:Java...

    一、背景:后台有很多任务,每个任务都是一个main函数(JVM或进程),但是所有的任务都加载同一个log4j.xml文件,即往同一份文件中输出日志。

    二、原因追踪

    在 log4j 的 DailyRollingFileAppender 类中:

    Java代码  收藏代码
    1. void rollOver() throws IOException {  
    2.   
    3.     /* Compute filename, but only if datePattern is specified */  
    4.     if (datePattern == null) {  
    5.       errorHandler.error("Missing DatePattern option in rollOver().");  
    6.       return;  
    7.     }  
    8.   
    9.     String datedFilename = fileName+sdf.format(now);  
    10.     // It is too early to roll over because we are still within the  
    11.     // bounds of the current interval. Rollover will occur once the  
    12.     // next interval is reached.  
    13.     if (scheduledFilename.equals(datedFilename)) {  
    14.       return;  
    15.     }  
    16.   
    17.     // close current file, and rename it to datedFilename  
    18.     this.closeFile();  
    19.   
    20.     File target  = new File(scheduledFilename);  
    21.     if (target.exists()) {  
    22.       target.delete();  
    23.     }  
    24.   
    25.     File file = new File(fileName);  
    26.     boolean result = file.renameTo(target);  
    27.     if(result) {  
    28.       LogLog.debug(fileName +" -> "+ scheduledFilename);  
    29.     } else {  
    30.       LogLog.error("Failed to rename ["+fileName+"] to ["+scheduledFilename+"].");  
    31.     }  
    32.   
    33.     try {  
    34.       // This will also close the file. This is OK since multiple  
    35.       // close operations are safe.  
    36.       this.setFile(fileName, falsethis.bufferedIO, this.bufferSize);  
    37.     }  
    38.     catch(IOException e) {  
    39.       errorHandler.error("setFile("+fileName+", false) call failed.");  
    40.     }  
    41.     scheduledFilename = datedFilename;  
    42. }  
    该方法的作用是:在滚动备份时间间隔到的时刻,将前一时间间隔的日志备份,同时以非追加模式将新日志打到新日志文件中;

    中间部分代码意思是:如果备份文件不存在,则备份,同时创建新日志文件;如果存在,则先删除掉,再备份;

     

    好,问题在这个时刻就出现了:(假设A进程先进行滚动备份)

    1、对于A进程:
    a. 先将project.log备份(renameTo())为project.log.2009.08.18,然后创建project.log文件,并将日志写在project.log中;
    b. 此时A进程持有project.log的文件句柄;而B进程仍然持有project.log.2009.08.18的文件句柄(尽管被重命名,但句柄不变);

    2、对于B进程:发现以project.log.2009.08.18为文件名的文件已经存在,则将其删除(前一时间段的所有日志全没了),并将以project.log为文件名的文件重命名为project.log.2009.08.18,然后创建project.log文件;

    3、此时A进程持有project.log.2009.08.18的文件句柄(被B进程重命名过的),而B进程持有最新创建的project.log

    4、结果导致:前一时间段日志丢失,A、B进程在不同的文件里打日志;

    三、解决方案

    1、改变 rollOver() 方法的实现方式:定义 TaskDailyRollingFileAppender 类,该类继承至 FileAppender ,它与 DailyRollingFileAppender 的主要区别在于以下方法:

    Java代码  收藏代码
    1. void rollOver() throws IOException {  
    2.   
    3.     /* Compute filename, but only if datePattern is specified */  
    4.     if (datePattern == null) {  
    5.       errorHandler.error("Missing DatePattern option in rollOver().");  
    6.       return;  
    7.     }  
    8.   
    9.     String datedFilename = fileName+sdf.format(now);  
    10.     // It is too early to roll over because we are still within the  
    11.     // bounds of the current interval. Rollover will occur once the  
    12.     // next interval is reached.  
    13.     if (scheduledFilename.equals(datedFilename)) {  
    14.       return;  
    15.     }  
    16.   
    17.     // close current file, and rename it to datedFilename  
    18.     this.closeFile();  
    19.   
    20.     File target  = new File(scheduledFilename);  
    21.     if (!target.exists()) {  
    22.         File file = new File(fileName);  
    23.         boolean result = file.renameTo(target);  
    24.         if (result) {  
    25.             LogLog.debug(fileName + " -> " + scheduledFilename);  
    26.         } else {  
    27.             LogLog.error("Failed to rename [" + fileName + "] to [" + scheduledFilename + "].");  
    28.         }  
    29.     }  
    30.   
    31.     try {  
    32.         // This will also close the file. This is OK since multiple  
    33.         // close operations are safe.  
    34.         this.setFile(fileName, truethis.bufferedIO, this.bufferSize);  
    35.     }  
    36.     catch(IOException e) {  
    37.       errorHandler.error("setFile("+fileName+", false) call failed.");  
    38.     }  
    39.     scheduledFilename = datedFilename;  
    40. }  
    改进后的 rollOver() 方法主要作用是:A进程先将日志重命名,然后创建新日志文件,B进程发现已经存在,则直接以追加模式切换到新的日志文件上去;

     

    2、如果是任务,根据启动参数taskName 属性区分日志文件:

    a. 目前所有后台任务在启动脚本里都加上了 -DtaskName 属性;
    b. 定义 TaskDailyRollingFileAppender 类,该类继承 DailyRollingFileAppender,并覆盖其 setFile(String file) 方法:

    Java代码  收藏代码
    1. public void setFile(String file) {  
    2.     String taskName = System.getProperty("taskName");  
    3.     if (!StringUtil.isEmpty(taskName)) {  
    4.         file = file + "." + taskName;  
    5.     }  
    6.   
    7.     super.setFile(file);  
    8. }  
     c. 这样实现后,对于不同的任务,日志文件名会以.taskName结尾,对于没有指定 taskName 的任务,不受影响;
    展开全文
  • log4j的强大功能无可置疑,但实际应用中免不了遇到某个功能需要输出独立的日志文件的情况,怎样才能把所需的内容从原有日志中分离,形成单独的日志文件呢?其实只要在现有的log4j基础上稍加配置即可轻松实现这一功能...
    最近在用多个线程走多个任务,但是日志用一个文件总有的线程输出不了。
    其他博客找的解决方法:
    log4j的强大功能无可置疑,但实际应用中免不了遇到某个功能需要输出独立的日志文件的情况,怎样才能把所需的内容从原有日志中分离,形成单独的日志文件呢?其实只要在现有的log4j基础上稍加配置即可轻松实现这一功能。
    1)先看一个常见的log4j.properties文件,它是在控制台和daily.log文件中记录日志:
    log4j.rootLogger=error,dailyLog,stdout
    log4j.appender.stdout=org.apache.log4j.ConsoleAppender
    log4j.appender.stdout.Target=System.out
    log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
    log4j.appender.stdout.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n
    log4j.appender.dailyLog=org.apache.log4j.DailyRollingFileAppender
    log4j.appender.dailyLog.File=../logs/daily.log
    log4j.appender.dailyLog.Append=true
    log4j.appender.dailyLog.Threshold=ERROR
    log4j.appender.dailyLog.DatePattern='.'yyyy-MM-dd
    log4j.appender.dailyLog.layout=org.apache.log4j.PatternLayout
    log4j.appender.dailyLog.layout.ConversionPattern=%5p:%d - %m%n

    2)如果想对不同的功能模块输出不同的文件,怎么操作?
    如:
    用户基础信息模块路径为:com.isoft.visa.baseinf
    它下面有个类:com.isoft.visa.baseinf.service.impl.UserInfo
    private Log log = LogFactory.getLog(UserInfo.class);
    然后在log4j.properties中加入:
    log4j.logger.com.isoft.visa.baseinf=info,userLog,stdout
    log4j.appender.userLog=org.apache.log4j.FileAppender
    log4j.appender.userLog.File=../logs/userinfo.log
    log4j.appender.userLog.Append=true
    log4j.appender.userLog.Threshold=info
    log4j.appender.userLog.layout=org.apache.log4j.PatternLayout
    log4j.appender.userLog.layout.ConversionPattern==%d %p [%c] - %m%n
    注:也就是让com.isoft.visa.baseinf模块下所有的logger使用log4j.appender.userLog所做的配置。

    3)自定义“别名”的使用,相当于2的变种。
    同上模块:
    private Log log = LogFactory.getLog("userInfoLog");
    然后在log4j.properties中加入:
    log4j.logger.userInfoLog=info,userLog,stdout
    log4j.appender.userLog=org.apache.log4j.FileAppender
    log4j.appender.userLog.File=../logs/userinfo.log
    log4j.appender.userLog.Append=true
    log4j.appender.userLog.Threshold=info
    log4j.appender.userLog.layout=org.apache.log4j.PatternLayout
    log4j.appender.userLog.layout.ConversionPattern==%d %p [%c] - %m%n
    注:也就是在用logger时给它一个自定义的名字(如这里的"userInfoLog"),然后在log4j.properties中做出相应配置即可。,在这种模式下,即使在同一个类中也能定义多个不同输出的log.
    在类中调用代码如下:
    private Log loggerError = LogFactory.getLog("userInfoLogError");
    private Log loggerInfo = LogFactory.getLog("userInfoLogInfo");

    4)自定义的日志默认是同时输出到log4j.rootLogger所配置的日志中的,如何能只让它们输出到自己指定的日志中呢?别急,这里有个开关:
    log4j.additivity.userInfoLog = false
     它用来设置是否同时输出到log4j.rootLogger所配置的日志中,设为false就不会输出到其它地方啦!注意这里的"userInfoLog"是你在程序中给logger起的那个自定义的名字!
    如果你说,我只是不想同时输出这个日志到log4j.rootLogger所配置的logfile中,stdout里我还想同时输出呢!那也好办,如:
    log4j.logger.userInfoLog=DEBUG, userLog, stdout
    展开全文
  • log4j2 多进程日志文件分离

    千次阅读 2016-11-01 20:21:34
    假设有一个jar包内有一个main方法:test 现在准备启动进程来执行这个test方法.并且每个进程输出的日志文件不相同. 1.在启动进程时自定义一个...2.在log4j2.xml内配置日志文件名时,以${sys:log4j.fileName} 的形式

    假设有一个jar包内有一个main方法:test

    现在准备启动多个进程来执行这个test方法.并且每个进程输出的日志文件不相同.

    1.在启动进程时自定义一个变量log4j.fileName, 如下:

    java -Dlog4j.fileName=name1 -cp **** test.test

    2.在log4j2.xml内配置日志文件名时,以${sys:log4j.fileName} 的形式获取第一步设定的参数name1,    示例如下

      <Appenders>
        <!-- Async Loggers will auto-flush in batches, so switch off immediateFlush. -->
        <RandomAccessFile name="RandomAccessFile" fileName="${sys:log4j.fileName}.log" immediateFlush="false" append="false">
          <PatternLayout>
            <Pattern>%d %p %c{1.} [%t] %m %ex%n</Pattern>
          </PatternLayout>
        </RandomAccessFile>
      </Appenders>


    展开全文
  • log4j同配置下进程日志

    千次阅读 2016-07-20 11:11:20
    由于起了两个不同的任务,log4j中用的是一套配置,写入的是同一个路径,导致日志文件丢失覆盖 准备配置个输出文件,但由于代码基本完成,而且各个类中的log实例由下面代码获取,改动起来挺费事 public static ...

    由于起了两个不同的任务,log4j中用的是一套配置,写入的是同一个路径,导致日志文件丢失覆盖

    准备配置多个输出文件,但由于代码基本完成,而且各个类中的log实例由下面代码获取,改动起来挺费事

    	public static final Logger log = LoggerFactory.getLogger(xx.class);
    
    找了下相关的资料,有个比较简单的方法,只需要在log4j的配置中,加入变量,然后启动java程序时附带上参数就好啦

    log4j.appender.FILE.File=~/logs/${log4j.logtype}.log
    

    启动附带参数

    java -Dlog4j.logtype=xx -cp ...




    展开全文
  • log4j 日志打印总结

    千次阅读 2015-01-27 15:27:30
    近段时间查看日志比较头疼,tomcat管控个项目下,日志输出会比较混乱,所以用到log4j 打印日志,今天徒步 就想大家介绍下log4j. 简介 Log4j是Apache的一个开放源代码项目,通过使用Log4j,我们可以控制日志信息...
  • 由于起了两个不同的任务,log4j中用的是一套配置,写入的是同一个路径,导致日志文件丢失覆盖 准备配置个输出文件,但由于代码基本完成,而且各个类中的log实例由下面代码获取,改动起来挺费事 public static ...
  • 解决log4j公用配置文件,多进程同时写同一个log文件,因存在操作系统pv操作问题, 导致部分日志丢失。解决方案是不同的进程写不同的log文件 测试于:Log4j 1.2.15 | CentOS 5.7 假设有个一个web项目,项目中同时...
  • 可以使用socketappender解决多进程... server端代码:[java] view plain copy package log4j; import org.apache.log4j.Logger; import org.apache.log4j.net.SimpleSocketServer; public class Server{ ...
  • Log4j是Apache的一个开放源代码项目,通过使用Log4j,我们只需进行简单的配置即可将应用程序的日志信息输送的到控制台、文件、GUI组件、甚至是套接口服务器、NT的事件记录器、UNIX Syslog守护进程等。Log4j中有三个...
  • 问题发现:项目使用log4j日志。公司使用的模式是log4j-wget下载日志-awk处理日志-入mysql 最近统计发现统计数据比日志严重少。而脚本数据库同步到测试机上,再执行竟然没错误。 后来才发现日志写入时间出错。比如x....
  • log4j2支持日志的异步打印,日志异步输出的好处在于,使用单独的进程来执行日志打印的功能,可以提高日志执行效率,减少日志功能对正常业务的影响。异步日志在程序的classpath需要加载disruptor-3.0.0.jar或者更高的...
  • 【背景】 前段时间在工作中发现,在nginx的自定义模块中使用log4j... 1)在log4j配置文件中设置的按天切割文件,由于有进程,每个进程都读同样的配置,写同样的日志文件。 2)nginx配置12个进程 现象: ...
  • log4j日志写在个文件里的方法

    千次阅读 2015-09-23 16:05:26
    因为最近写了一个定时程序,是定时扫表,并插入不同的指令表,发向两个网元。使用了4个独立的定时进程,其中每两个对应一个网元。因为每个网元相对独立,故此打算将日志分开记录。
  • 了解log4j是躲不掉的

    2020-04-24 10:29:02
    Log4j是Apache的一个开源项目,通过使用Log4j,我们可以控制日志信息输送的目的地是控制台、文件、GUI组件,甚至是套接口服务器、NT的事件记录器、UNIX Syslog守护进程等;我们也可以控制每一条日志的输出格式;通过...
  • 这个进程中,日志查看的问题逐渐暴露出来。 首先,分布式系统,程序部署在不同的机器上,查询日志需要登录到各台机器上,很不方便;其次,云服务使用 Docker 虚拟技术,当服务重新部署时,机器上的文件会全部抹除,...
  • log4j,Log4j是Apache的一个开放源代码项目,通过使用Log4j,我们可以控制日志信息输送的目的地是控制台、文件、GUI组件,甚至是套接口服务器、NT的事件记录器、UNIXSyslog守护进程等。 参考资料:易百教程»Log4j...
  • 日志处理是每一个项目开发中必须的,很公司自己独立自主开发自己的日志组件,除了自己从头到尾开发一个可重用的日志操作类外,Apache为我们提供了一个强有力的日志操作包-Log4j。  Log4j是Apache的一个开放源...
  • 研究之后将所有对数据库的连接方式改用了数据库连接池(dbcp)的方式,果然各个操作的效率提高了很,不过出现了一个问题,我的日志部分是利用log4j来实现的,在我对数据库操作中与一个功能是对数据库的备份和恢复...
  • Java 中最通用的日志模块莫过于 Log4j 了,在 python 中,也自带了 logging 模块,该模块的用法其实和 Log4j 类似。日志是记录操作的一种好方式。但是日志,基本都是基于文件的,也就是要写到磁盘上的。这时候,磁盘...
  • 网上有关LOG4J的配置很,其中也有不少提到:“可以控制日志信息输送的目的地是控制台、文件、GUI组件、甚至是套接口服务器、NT的事件记录器、UNIX Syslog守护进程等”。我想把目志输出到JTextArea,网上搜了很久,...
  • log4cxx用环境变量设置输出文件名

    千次阅读 2016-12-05 15:28:57
    log4cxx用环境变量设置输出文件名(金庆的专栏 2016.12)利用环境变量,可以用同一个log4j.xml来配置个相似进程,输出日志到不同文件。例如个BaseApp进程使用同一个BaseApp.xml配置, SERVER_ID为环境变量: ... ...

空空如也

空空如也

1 2 3 4
收藏数 65
精华内容 26
关键字:

多进程log4j日志