log4j删除N天前日志实现

本文涉及的产品
日志服务 SLS,月写入数据量 50GB 1个月
简介:

基于Log4j完成定时创建和删除日志的方法

1.     背景

最近要实现定期删除N天前的日志需求:

Log4j作为常用的日志生成工具,其清除日志的策略却十分有限。只有在RollingFileAppender中可以通过设置MaxFileSizemaxBackupIndex属性来指定要保留的日志文件大小以及个数,从而实现自动清除。

 wKioL1mJbtaC1NXLAAATocqgGk4000.png

但是实际生产中,我们的真实的需求常常是定时每天生成一个日志文件,然后保留最近几天或近几个月的日志,历史日志需要及时清理。可是Log4j中的DailyRollingFileAppender这个类却不带属性maxBackupIndex,maxFileSize等,所以无法通过直接配置实现。

 

针对这种情况,可以是写一个定时删除日志的脚本,也可以是重新实现DailyRollingFileAppender

这里我们通过继承FileAppender,重新实现DailyRollingFileAppender类,带有按时间顺序删除N天前的日志文件的功能。

2.具体实现

2.1代码实现

package com.demo.filter;

 

import java.io.File;

import java.io.FilenameFilter;

import java.io.IOException;

importjava.io.InterruptedIOException;

import java.io.Serializable;

import java.net.URI;

importjava.text.SimpleDateFormat;

import java.util.ArrayList;

import java.util.Calendar;

import java.util.Collections;

import java.util.Date;

importjava.util.GregorianCalendar;

import java.util.List;

import java.util.Locale;

import java.util.TimeZone;

 

importorg.apache.log4j.FileAppender;

import org.apache.log4j.Layout;

importorg.apache.log4j.helpers.LogLog;

importorg.apache.log4j.spi.LoggingEvent;

 

/**

 *

 * @项目名称:wupao-job

 * @类名称:CustomDailyRollingFileAppender

 * @类描述:DailyRollingFileAppender extendsFileAppender

 * </br>重写RollingFileAppender

 * </br>实现maxBackupIndex限制日志文件数量功能(定时删除超过N天前的日志文件)

 * @创建人:wyait

 * @创建时间:201788下午2:40:38

 * @version1.0.0

 */

public classCustomDailyRollingFileAppender extends FileAppender {

   //初始化参数

   staticfinal int TOP_OF_TROUBLE = -1;

   staticfinal int TOP_OF_MINUTE = 0;

   staticfinal int TOP_OF_HOUR = 1;

   staticfinal int HALF_DAY = 2;

   staticfinal int TOP_OF_DAY = 3;

   staticfinal int TOP_OF_WEEK = 4;

   staticfinal int TOP_OF_MONTH = 5;

 

   /**

    *生产日志文件后缀"'.'yyyy-MM-dd"

    */

   privateString datePattern = "'.'yyyy-MM-dd";

   /**

    * 默认:1个日志文件

    */

   protectedint maxBackupIndex = 1;

 

   /**

    * 保存前一天的日志文件名称 =filename+("'.'yyyy-MM-dd")

    */

   privateString scheduledFilename;

 

   //The next time we estimate a rollover should occur.

   privatelong nextCheck = System.currentTimeMillis() - 1;

 

   Datenow = new Date();

 

   SimpleDateFormatsdf;

 

   RollingCalendarrc = new RollingCalendar();

 

   intcheckPeriod = TOP_OF_TROUBLE;

 

   //The gmtTimeZone is used only in computeCheckPeriod() method.

   staticfinal TimeZone gmtTimeZone = TimeZone.getTimeZone("GMT");

 

   //无参构造

   publicCustomDailyRollingFileAppender() {

   }

 

   /**有参构造

     Instantiate a<code>DailyRollingFileAppender</code> and open the

     file designated by<code>filename</code>. The opened filename will

     become the ouput destination for thisappender.

    */

   publicCustomDailyRollingFileAppender(Layout layout, String filename,

        StringdatePattern) throws IOException {

      super(layout,filename, true);

      this.datePattern= datePattern;

      activateOptions();

   }

 

   publicvoid setDatePattern(String pattern) {

      datePattern= pattern;

   }

 

   publicvoid setMaxBackupIndex(int maxBackups) {

      this.maxBackupIndex= maxBackups;

   }

 

   publicint getMaxBackupIndex() {

      returnmaxBackupIndex;

   }

 

   publicString getDatePattern() {

      returndatePattern;

   }

 

   @Override

   publicvoid activateOptions() {

      super.activateOptions();

      if(datePattern != null && fileName != null) {

        now.setTime(System.currentTimeMillis());

        sdf= new SimpleDateFormat(datePattern);

        inttype = computeCheckPeriod();

        printPeriodicity(type);

        rc.setType(type);

        Filefile = new File(fileName);

        scheduledFilename= fileName

              +sdf.format(new Date(file.lastModified()));

 

      }else {

        LogLog.error("EitherFile or DatePattern options are not set for appender ["

              +name + "].");

      }

   }

 

   voidprintPeriodicity(int type) {

      switch(type) {

      caseTOP_OF_MINUTE:

        LogLog.debug("Appender[" + name + "] to be rolled every minute.");

        break;

      caseTOP_OF_HOUR:

        LogLog.debug("Appender[" + name

              +"] to be rolled on top of every hour.");

        break;

      caseHALF_DAY:

        LogLog.debug("Appender[" + name

              +"] to be rolled at midday and midnight.");

        break;

      caseTOP_OF_DAY:

        LogLog.debug("Appender[" + name + "] to be rolled at midnight.");

        break;

      caseTOP_OF_WEEK:

        LogLog.debug("Appender[" + name

              +"] to be rolled at start of week.");

        break;

      caseTOP_OF_MONTH:

        LogLog.debug("Appender[" + name

              +"] to be rolled at start of every month.");

        break;

      default:

        LogLog.warn("Unknownperiodicity for appender [" + name + "].");

      }

   }

 

   //This method computes the roll over period by looping over the

   //periods, starting with the shortest, and stopping when the r0 is

   //different from from r1, where r0 is the epoch formatted according

   //the datePattern (supplied by the user) and r1 is the

   //epoch+nextMillis(i) formatted according to datePattern. All date

   //formatting is done in GMT and not local format because the test

   //logic is based on comparisons relative to 1970-01-01 00:00:00

   //GMT (the epoch).

 

   intcomputeCheckPeriod() {

      RollingCalendarrollingCalendar = new RollingCalendar(gmtTimeZone,

           Locale.getDefault());

      //set sate to 1970-01-01 00:00:00 GMT

      Dateepoch = new Date(0);

      if(datePattern != null) {

        for(int i = TOP_OF_MINUTE; i <= TOP_OF_MONTH; i++) {

           SimpleDateFormatsimpleDateFormat = new SimpleDateFormat(

                 datePattern);

           simpleDateFormat.setTimeZone(gmtTimeZone);// do all date

                                          //formatting in GMT

           Stringr0 = simpleDateFormat.format(epoch);

           rollingCalendar.setType(i);

           Datenext = new Date(rollingCalendar.getNextCheckMillis(epoch));

           Stringr1 = simpleDateFormat.format(next);

           //System.out.println("Type = "+i+", r0 = "+r0+", r1 ="+r1);

           if(r0 != null && r1 != null && !r0.equals(r1)) {

              returni;

           }

        }

      }

      returnTOP_OF_TROUBLE; // Deliberately head for trouble...

   }

 

   /**核心方法:生成日志文件,并完成对备份数量的监测以及历史日志的删除

      Rollover the current file to a new file.

    */

   voidrollOver() throws IOException {

      //获取所有日志历史文件:并完成对备份数量的监测以及历史日志的删除

      List<ModifiedTimeSortableFile>files = getAllFiles();

      Collections.sort(files);

      if(files.size() >= maxBackupIndex) {

        intindex = 0;

        intdiff = files.size() - (maxBackupIndex - 1);

        for(ModifiedTimeSortableFile file : files) {

           if(index >= diff)

              break;

 

           file.delete();

           index++;

        }

      }

 

      /*Compute filename, but only if datePattern is specified */

      if(datePattern == null) {

        errorHandler.error("MissingDatePattern option in rollOver().");

        return;

      }

      LogLog.debug("maxBackupIndex="+ maxBackupIndex);

 

      StringdatedFilename = fileName + sdf.format(now);

      //It is too early to roll over because we are still within the

      //bounds of the current interval. Rollover will occur once the

      //next interval is reached.

      if(scheduledFilename.equals(datedFilename)) {

        return;

      }

 

      //close current file, and rename it to datedFilename

      this.closeFile();

 

      Filetarget = new File(scheduledFilename);

      if(target.exists()) {

        target.delete();

      }

 

      Filefile = new File(fileName);

      booleanresult = file.renameTo(target);

      if(result) {

        LogLog.debug(fileName+ " -> " + scheduledFilename);

      }else {

        LogLog.error("Failedto rename [" + fileName + "] to ["

              +scheduledFilename + "].");

      }

 

      try{

        //This will also close the file. This is OK since multiple

        //close operations are safe.

        this.setFile(fileName,true, this.bufferedIO, this.bufferSize);

      }catch (IOException e) {

        errorHandler.error("setFile("+ fileName + ", true) call failed.");

      }

      scheduledFilename= datedFilename;

   }

 

   /**

    * This method differentiatesDailyRollingFileAppender from its

    * super class.

    *

    * <p>Before actually logging, thismethod will check whether it is

    * time to do a rollover. If it is, it willschedule the next

    * rollover time and then rollover.

    * */

   @Override

   protectedvoid subAppend(LoggingEvent event) {

      longn = System.currentTimeMillis();

      if(n >= nextCheck) {

        now.setTime(n);

        nextCheck= rc.getNextCheckMillis(now);

        try{

           rollOver();

        }catch (IOException ioe) {

           if(ioe instanceof InterruptedIOException) {

              Thread.currentThread().interrupt();

           }

           LogLog.error("rollOver()failed.", ioe);

        }

      }

      super.subAppend(event);

   }

 

   /**

    * 获取同一项目日志目录下所有文件

    * This method searches list of log files

    * based on the pattern given in the log4jconfiguration file

    * and returns a collection 

    * @returnList&lt;ModifiedTimeSortableFile&gt;

    */

   privateList<ModifiedTimeSortableFile> getAllFiles() {

      List<ModifiedTimeSortableFile>files = new ArrayList<ModifiedTimeSortableFile>();

      FilenameFilterfilter = new FilenameFilter() {

        //重写accept方法,确认是否是同一项目日志文件名称前缀。

        @Override

        publicboolean accept(File dir, String name) {

           StringdirectoryName = dir.getPath();

           LogLog.debug("directoryname: " + directoryName);

           Filefile = new File(fileName);

           StringperentDirectory = file.getParent();

           if(perentDirectory != null) {

              //name=demo.log

              //directoryName= /logs 

              //直接fileName.substring(directoryName.length());切割之后的localFile=/demo.log…,会导致name.startsWith(localFile)始终是false

              //so解决方案:长度 +1

              StringlocalFile = fileName.substring(directoryName

                    .length()+ 1);

              returnname.startsWith(localFile);

           }

           returnname.startsWith(fileName);

        }

      };

      Filefile = new File(fileName);

      StringperentDirectory = file.getParent();

      if(file.exists()) {

        if(file.getParent() == null) {

           StringabsolutePath = file.getAbsolutePath();

           perentDirectory= absolutePath.substring(0,

                 absolutePath.lastIndexOf(fileName));

 

        }

      }

      Filedir = new File(perentDirectory);

      String[]names = dir.list(filter);

 

      for(int i = 0; i < names.length; i++) {

        files.add(newModifiedTimeSortableFile(dir

              +System.getProperty("file.separator") + names[i]));

      }

      returnfiles;

   }

}

 

/** 自定义file类,重写compareTo方法,比较文件的修改时间

* The ClassModifiedTimeSortableFile extends java.io.File class and

* implements Comparable to sortfiles list based upon their modified date

*/

class ModifiedTimeSortableFileextends File implements Serializable,

      Comparable<File>{

   privatestatic final long serialVersionUID = 1373373728209668895L;

 

   publicModifiedTimeSortableFile(String parent, String child) {

      super(parent,child);

      //TODO Auto-generated constructor stub

   }

 

   publicModifiedTimeSortableFile(URI uri) {

      super(uri);

      //TODO Auto-generated constructor stub

   }

 

   publicModifiedTimeSortableFile(File parent, String child) {

      super(parent,child);

   }

 

   publicModifiedTimeSortableFile(String string) {

      super(string);

   }

 

   @Override

   publicint compareTo(File anotherPathName) {

      longthisVal = this.lastModified();

      longanotherVal = anotherPathName.lastModified();

      return(thisVal < anotherVal ? -1 : (thisVal == anotherVal ? 0 : 1));

   }

}

 

/**

*  RollingCalendar is a helper class toDailyRollingFileAppender.

*  Given a periodicity type and the currenttime, it computes the

*  start of the next interval. 

* */

class RollingCalendar extendsGregorianCalendar {

 

   privatestatic final long serialVersionUID = -8295691444111406775L;

 

   inttype = CustomDailyRollingFileAppender.TOP_OF_TROUBLE;

 

   RollingCalendar(){

      super();

   }

 

   RollingCalendar(TimeZonetz, Locale locale) {

      super(tz,locale);

   }

 

   voidsetType(int type) {

      this.type= type;

   }

 

   publiclong getNextCheckMillis(Date now) {

      returngetNextCheckDate(now).getTime();

   }

 

   publicDate getNextCheckDate(Date now) {

      this.setTime(now);

 

      switch(type) {

      caseCustomDailyRollingFileAppender.TOP_OF_MINUTE:

        this.set(Calendar.SECOND,0);

        this.set(Calendar.MILLISECOND,0);

        this.add(Calendar.MINUTE,1);

        break;

      caseCustomDailyRollingFileAppender.TOP_OF_HOUR:

        this.set(Calendar.MINUTE,0);

        this.set(Calendar.SECOND,0);

        this.set(Calendar.MILLISECOND,0);

        this.add(Calendar.HOUR_OF_DAY,1);

        break;

      caseCustomDailyRollingFileAppender.HALF_DAY:

        this.set(Calendar.MINUTE,0);

        this.set(Calendar.SECOND,0);

        this.set(Calendar.MILLISECOND,0);

        inthour = get(Calendar.HOUR_OF_DAY);

        if(hour < 12) {

           this.set(Calendar.HOUR_OF_DAY,12);

        }else {

           this.set(Calendar.HOUR_OF_DAY,0);

           this.add(Calendar.DAY_OF_MONTH,1);

        }

        break;

      caseCustomDailyRollingFileAppender.TOP_OF_DAY:

        this.set(Calendar.HOUR_OF_DAY,0);

        this.set(Calendar.MINUTE,0);

        this.set(Calendar.SECOND,0);

        this.set(Calendar.MILLISECOND,0);

        this.add(Calendar.DATE,1);

        break;

      caseCustomDailyRollingFileAppender.TOP_OF_WEEK:

        this.set(Calendar.DAY_OF_WEEK,getFirstDayOfWeek());

        this.set(Calendar.HOUR_OF_DAY,0);

        this.set(Calendar.MINUTE,0);

        this.set(Calendar.SECOND,0);

        this.set(Calendar.MILLISECOND,0);

        this.add(Calendar.WEEK_OF_YEAR,1);

        break;

      caseCustomDailyRollingFileAppender.TOP_OF_MONTH:

        this.set(Calendar.DATE,1);

        this.set(Calendar.HOUR_OF_DAY,0);

        this.set(Calendar.MINUTE,0);

        this.set(Calendar.SECOND,0);

        this.set(Calendar.MILLISECOND,0);

        this.add(Calendar.MONTH,1);

        break;

      default:

        thrownew IllegalStateException("Unknown periodicity type.");

      }

      returngetTime();

   }

 

}

2.2配置实现

resources目录下,自定义log4j.xml日志配置文件:

<?xml version="1.0"encoding="UTF-8"?>

<!DOCTYPE log4j:configurationSYSTEM "log4j.dtd" >

<log4j:configuration>

<!-- 引用自定义的CustomDailyRollingFileAppender日志类-->

   <appender name="FILE"class="com.demo.filter.CustomDailyRollingFileAppender">

     <!-- 自定义日志输出路径和名称 -->

      <param name="file"value="D:/logs/test-agent.log" />

      <!-- 自定义历史日志文件后缀名 -->

      <param name="datePattern"value="'.'yyyy-MM-dd" />

      <!-- 自定义日志文件总数量,大于这个数量,自动删除 -->

      <param name="maxBackupIndex"value="3" />

      <param name="append"value="true" />

      <layoutclass="org.apache.log4j.PatternLayout">

         <paramname="ConversionPattern" value="%d [%t] %p - %m%n" />

      </layout>

   </appender>

   <root>

      <priority value="info" />

      <appender-ref ref="FILE"/>

   </root>

</log4j:configuration>

2.3 测试类

main方法:

public static voidmain1(String[] args) {

      finalFile file = new File("log4j.xml");

 

      if(file.exists()) {

        finalURL url = Main.class.getClassLoader()

              .getResource("log4j.xml");

        StringconfigFile = url.getPath();

        PropertyConfigurator.configure("log4j.xml");

      }

 

      log.trace("Trace");

      log.debug("Debug");

      log.info("Info");

      log.warn("Warn");

      log.error("Error");

      log.fatal("Fatal");

   }

 

第一次启动:

wKioL1mJbu_SEokyAAAFWuikluo005.png

手动创建几个其他日期的历史文件:

wKiom1mJbv2hkB6xAAATlMzTdyw223.png

第二次启动:

wKiom1mJbxygWBc2AAAQarCncj8386.png

 

2.4项目log4j实战配置

log4j.rootLogger=INFO,demo

log4j.logger.org.mybatis = INFO

log4j.appender.demo=org.apache.log4j.ConsoleAppender

log4j.appender.demo.layout=org.apache.log4j.PatternLayout

log4j.appender.demo.layout.ConversionPattern=%m%n

 

log4j.appender.demo=com.demo.filter.CustomDailyRollingFileAppender

#log4j.appender.demo=org.apache.log4j.RollingFileAppender

log4j.appender.demo.File=D:/logs/demo.log

#log4j.appender.demo.Threshold=INFO

#log4j.appender.demo.ImmediateFlush=true

#log4j.appender.demo.Append=true

log4j.appender.demo.maxBackupIndex=3

log4j.appender.demo.layout.ConversionPattern=[%d{yyyy:MM:dd HH:mm:ss}]:%m \r\n

log4j.appender.demoConsole.encoding=utf-8

log4j.appender.demoConsole=org.apache.log4j.ConsoleAppender

log4j.appender.demoConsole.Target= System.out

log4j.appender.demoConsole.layout=org.apache.log4j.PatternLayout

log4j.appender.demoConsole.layout.ConversionPattern= [%d{yyyy:MM:dd HH:mm:ss}]:%m \r\n

3.Log4j相关配置的含义

Log4j由三个重要的组件构成:日志信息的优先级,日志信息的输出目的地,日志信息的输出格式。日志信息的优先级从高到低有ERROR、WARN、 INFO、DEBUG,分别用来指定这条日志信息的重要程度;日志信息的输出目的地指定了日志将打印到控制台还是文件中;而输出格式则控制了日志信息的显示内容。Log4j支持两种配置文件格式,一种是XML格式的文件,一种是Java特性文件(键=值)。这里,我们主要探讨基于XML的配置方式。

3.1配置根logger

基本语法是:

 wKiom1mJbyzBqxWtAAAGGCnS7OM708.png

其中,level 是日志记录的优先级,分为OFFFATALERRORWARNINFODEBUGALL或者您定义的级别。Log4j建议只使用四个级别,优先级从高到低分别是ERRORWARNINFODEBUG

 

这里,每一个appenderName均是下面需要配置的日志信息的名称。

 

实际例子:

log4j.rootLogger=INFO,stdout, ROLLING_ERROR_FILE, ROLLING_INFO_FILE

wKioL1mJbzmC_-W4AAAN50s-ois849.png

3.2配置日志信息输出目的地Appeder

Log4j中提供的Appender主要有以下几种:

 

org.apache.log4j.ConsoleAppender(控制台), 

org.apache.log4j.FileAppender(文件), 

org.apache.log4j.DailyRollingFileAppender(每天产生一个日志文件), 

org.apache.log4j.RollingFileAppender(文件大小到达指定尺寸的时候产生一个新的文件), 

org.apache.log4j.WriterAppender(将日志信息以流格式发送到任意指定的地方)

 

基本语法为:

wKiom1mJb0aDVbrlAAAN55lgnGo570.png

 

实际例子:

 

log4j.appender.ROLLING_ERROR_FILE=org.apache.log4j.DailyRollingFileAppender

针对不同的Appender,它们的属性也有一定的差别,这些属性主要是针对日志文件的命名规则、保存路径、删除策略等有关系。

3.2.1 ConsoleAppender的属性

Threshold=WARN:指定日志信息的最低输出级别,默认为DEBUG

ImmediateFlush=true:表示所有消息都会被立即输出,设为false则不输出,默认值是true

Target=System.err:默认值是System.out

3.2.2 FileAppender的属性

Threshold=WARN:指定日志信息的最低输出级别,默认为DEBUG

ImmediateFlush=true:表示所有消息都会被立即输出,设为false则不输出,默认值是true

Append=falsetrue表示消息增加到指定文件中,false则将消息覆盖指定的文件内容,默认值是true

File=D:/logs/logging.log4j:指定消息输出到logging.log4j文件中。

3.2.3 DailyRollingFileAppender的属性

Threshold=WARN:指定日志信息的最低输出级别,默认为DEBUG

ImmediateFlush=true:表示所有消息都会被立即输出,设为false则不输出,默认值是true

Append=falsetrue表示消息增加到指定文件中,false则将消息覆盖指定的文件内容,默认值是true

File=D:/logs/logging.log4j:指定当前消息输出到logging.log4j文件中。

DatePattern='.'yyyy-MM:每月滚动一次日志文件,即每月产生一个新的日志文件。当前月的日志文件名为logging.log4j,前一个月的日志文件名为logging.log4j.yyyy-MM

 

另外,也可以指定按周、天、时、分等来滚动日志文件,对应的格式如下:

 

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.2.4 RollingFileAppender的属性

Threshold=WARN:指定日志信息的最低输出级别,默认为DEBUG

ImmediateFlush=true:表示所有消息都会被立即输出,设为false则不输出,默认值是true

Append=falsetrue表示消息增加到指定文件中,false则将消息覆盖指定的文件内容,默认值是true

File=D:/logs/logging.log4j:指定消息输出到logging.log4j文件中。

MaxFileSize=100KB:后缀可以是KB, MB 或者GB。在日志文件到达该大小时,将会自动滚动,即将原来的内容移到logging.log4j.1文件中。

MaxBackupIndex=2:指定可以产生的滚动文件的最大数,例如,设为2则可以产生logging.log4j.1logging.log4j.2两个滚动文件和一个logging.log4j文件。

3.3 配置日志信息的格式(布局)layout

Log4j提供的layout有以下几种:

 

org.apache.log4j.HTMLLayout(以HTML表格形式布局), 

org.apache.log4j.PatternLayout(可以灵活地指定布局模式), 

org.apache.log4j.SimpleLayout(包含日志信息的级别和信息字符串), 

org.apache.log4j.TTCCLayout(包含日志产生的时间、线程、类别等等信息)

 

Log4j采用类似C语言中的printf函数的打印格式格式化日志信息,打印参数如下:

 

%m 输出代码中指定的消息

%p 输出优先级,即DEBUGINFOWARNERRORFATAL 

%r 输出自应用启动到输出该log信息耗费的毫秒数 

%c 输出所属的类目,通常就是所在类的全名 

%t 输出产生该日志事件的线程名 

%n 输出一个回车换行符,Windows平台为“rn”Unix平台为“n” 

%d 输出日志时间点的日期或时间,默认格式为ISO8601,也可以在其后指定格式,比如:%d{yyy MMM dd HH:mm:ss,SSS},输出类似:20021018 221028921 

%l 输出日志事件的发生位置,包括类目名、发生的线程,以及在代码中的行数。举例:Testlog4.main(TestLog4.java:10)

 

 

基本语法为:

wKioL1mJb0_wxPMZAAAPo-QG6Qo478.png

实际例子:

log4j.appender.ROLLING_ERROR_FILE.layout=org.apache.log4j.PatternLayout

log4j.appender.ROLLING_ERROR_FILE.layout.ConversionPattern=[log]%d -%-4r [%



本文转自 wyait 51CTO博客,原文链接:http://blog.51cto.com/wyait/1954507,如需转载请自行联系原作者

相关实践学习
日志服务之使用Nginx模式采集日志
本文介绍如何通过日志服务控制台创建Nginx模式的Logtail配置快速采集Nginx日志并进行多维度分析。
相关文章
|
1月前
|
XML 安全 Java
【日志框架整合】Slf4j、Log4j、Log4j2、Logback配置模板
本文介绍了Java日志框架的基本概念和使用方法,重点讨论了SLF4J、Log4j、Logback和Log4j2之间的关系及其性能对比。SLF4J作为一个日志抽象层,允许开发者使用统一的日志接口,而Log4j、Logback和Log4j2则是具体的日志实现框架。Log4j2在性能上优于Logback,推荐在新项目中使用。文章还详细说明了如何在Spring Boot项目中配置Log4j2和Logback,以及如何使用Lombok简化日志记录。最后,提供了一些日志配置的最佳实践,包括滚动日志、统一日志格式和提高日志性能的方法。
271 30
【日志框架整合】Slf4j、Log4j、Log4j2、Logback配置模板
|
6天前
|
监控 安全 Apache
什么是Apache日志?为什么Apache日志分析很重要?
Apache是全球广泛使用的Web服务器软件,支持超过30%的活跃网站。它通过接收和处理HTTP请求,与后端服务器通信,返回响应并记录日志,确保网页请求的快速准确处理。Apache日志分为访问日志和错误日志,对提升用户体验、保障安全及优化性能至关重要。EventLog Analyzer等工具可有效管理和分析这些日志,增强Web服务的安全性和可靠性。
|
2月前
|
XML JSON Java
Logback 与 log4j2 性能对比:谁才是日志框架的性能王者?
【10月更文挑战第5天】在Java开发中,日志框架是不可或缺的工具,它们帮助我们记录系统运行时的信息、警告和错误,对于开发人员来说至关重要。在众多日志框架中,Logback和log4j2以其卓越的性能和丰富的功能脱颖而出,成为开发者们的首选。本文将深入探讨Logback与log4j2在性能方面的对比,通过详细的分析和实例,帮助大家理解两者之间的性能差异,以便在实际项目中做出更明智的选择。
301 3
|
16天前
|
存储 监控 安全
什么是事件日志管理系统?事件日志管理系统有哪些用处?
事件日志管理系统是IT安全的重要工具,用于集中收集、分析和解释来自组织IT基础设施各组件的事件日志,如防火墙、路由器、交换机等,帮助提升网络安全、实现主动威胁检测和促进合规性。系统支持多种日志类型,包括Windows事件日志、Syslog日志和应用程序日志,通过实时监测、告警及可视化分析,为企业提供强大的安全保障。然而,实施过程中也面临数据量大、日志管理和分析复杂等挑战。EventLog Analyzer作为一款高效工具,不仅提供实时监测与告警、可视化分析和报告功能,还支持多种合规性报告,帮助企业克服挑战,提升网络安全水平。
|
2月前
|
存储 缓存 关系型数据库
MySQL事务日志-Redo Log工作原理分析
事务的隔离性和原子性分别通过锁和事务日志实现,而持久性则依赖于事务日志中的`Redo Log`。在MySQL中,`Redo Log`确保已提交事务的数据能持久保存,即使系统崩溃也能通过重做日志恢复数据。其工作原理是记录数据在内存中的更改,待事务提交时写入磁盘。此外,`Redo Log`采用简单的物理日志格式和高效的顺序IO,确保快速提交。通过不同的落盘策略,可在性能和安全性之间做出权衡。
1684 14
|
28天前
|
存储 监控 安全
什么是日志管理,如何进行日志管理?
日志管理是对IT系统生成的日志数据进行收集、存储、分析和处理的实践,对维护系统健康、确保安全及获取运营智能至关重要。本文介绍了日志管理的基本概念、常见挑战、工具的主要功能及选择解决方案的方法,强调了定义管理目标、日志收集与分析、警报和报告、持续改进等关键步骤,以及如何应对数据量大、安全问题、警报疲劳等挑战,最终实现日志数据的有效管理和利用。
|
2月前
|
Python
log日志学习
【10月更文挑战第9天】 python处理log打印模块log的使用和介绍
40 0
|
2月前
|
数据可视化
Tensorboard可视化学习笔记(一):如何可视化通过网页查看log日志
关于如何使用TensorBoard进行数据可视化的教程,包括TensorBoard的安装、配置环境变量、将数据写入TensorBoard、启动TensorBoard以及如何通过网页查看日志文件。
257 0
|
2月前
|
存储 分布式计算 NoSQL
大数据-136 - ClickHouse 集群 表引擎详解1 - 日志、Log、Memory、Merge
大数据-136 - ClickHouse 集群 表引擎详解1 - 日志、Log、Memory、Merge
53 0
|
2月前
|
缓存 Linux 编译器
【C++】CentOS环境搭建-安装log4cplus日志组件包及报错解决方案
通过上述步骤,您应该能够在CentOS环境中成功安装并使用log4cplus日志组件。面对任何安装或使用过程中出现的问题,仔细检查错误信息,对照提供的解决方案进行调整,通常都能找到合适的解决之道。log4cplus的强大功能将为您的项目提供灵活、高效的日志管理方案,助力软件开发与维护。
65 0