02、Log4j(第三方日志框架,带源码分析)(二)

本文涉及的产品
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
日志服务 SLS,月写入数据量 50GB 1个月
云数据库 RDS MySQL,高可用系列 2核4GB
简介: 02、Log4j(第三方日志框架,带源码分析)(二)

五、Log4j内置的日志LogLog


5.1、LogLog源码分析以及开启其debug模式*


LogLog:它是Log4j内置的Log,能够记录自身执行的过程信息,内部统一了开关的判断。


目的:可以观察配置信息,便于后期维护。

引出LogLog类


在LogManager类源码中我们可以看到需要LogLog进行打日志的操作,如下:


public class LogManager {
    //静态代码块中
    static{
        ...
              if(url != null) {
                LogLog.debug("Using URL ["+url+"] for automatic log4j configuration.");
                try {
                    OptionConverter.selectAndConfigure(url, configuratorClassName,
                               LogManager.getLoggerRepository());
                } catch (NoClassDefFoundError e) {
                    //若是在初始化配置时出现异常打了warn级别日志
                    LogLog.warn("Error during default initialization", e);
                }
              } else {
                 //资源没找到,打了debug日志
                LogLog.debug("Could not find resource: ["+configurationOptionStr+"].");
              }
            } else {
                LogLog.debug("Default initialization of overridden by " + 
                    DEFAULT_INIT_OVERRIDE_KEY + "property."); 
            }  
      ...
    }
  //静态方法中
  static public LoggerRepository getLoggerRepository() {
    if (repositorySelector == null) {
        repositorySelector = new DefaultRepositorySelector(new NOPLoggerRepository());
        guard = null;
        Exception ex = new IllegalStateException("Class invariant violation");
        String msg =
                "log4j called after unloading, see http://logging.apache.org/log4j/1.2/faq.html#unload.";
        //在判断是否是可能的安全方案中,调用了LogLog进行日志输出
        if (isLikelySafeScenario(ex)) {
            LogLog.debug(msg, ex);
        } else {
            LogLog.error(msg, ex);
        }
    }
    return repositorySelector.getLoggerRepository();
  }
}



此时我们会抛出疑问,为什么明明打了不同的日志等级在显示器中并不显示呢?我们依旧去看LogLog类源码:



LogLog源码


LogLog类:其是单独的一个类



可以看到其中包含了debug、error、warn这几个日志等级的方法。

public class LogLog {
      //默认都是false
      protected static boolean debugEnabled = false;  
      private static boolean quietMode = false;
      //error方法,默认会输出err问题
      public static void error(String msg) {
            if(quietMode)
               return;
            System.err.println(ERR_PREFIX+msg);
      }  
      //debug方法
      public static void debug(String msg) {
            //由于debugEnabled是false,所以不会执行方法体内容
            if(debugEnabled && !quietMode) {
              System.out.println(PREFIX+msg);
            }
      }
      //warn方法,默认是会输出错误情况
      void warn(String msg) {
            if(quietMode)
              return;
            System.err.println(WARN_PREFIX+msg);
      }  
}



通过看源码我们得知,对于进行debug的调试日志是默认关闭的,而对于warn、error警告及错误信息默认是会输出的。这样其实我们就能知晓为什么在第三部分没有进行配置rootlogger时的报错信息了!!!


开启LogLog的debug模式


那么我们怎么样开启调试debug信息呢?其实在LogLog类中给我们提供了一个方法可以设置debugEnabled的布尔值!源码如下:


/**
   Allows to enable/disable log4j internal logging.
 */
static public void setInternalDebugging(boolean enabled) {
  debugEnabled = enabled;
}


那么我们赶紧试试调用方法将debugEnabled设置true之后日志调试的效果吧。


开启:LogLog.setInternalDebugging(true);



我们使用4.3中的案例(自定义log4j.properties)进行测试:


import org.apache.log4j.Logger;
import org.apache.log4j.helpers.LogLog;
public class LogTest {
    public static void main(String[] args) {
        //开启LogLog的debug模式
        LogLog.setInternalDebugging(true);
        //获取logger实例
        Logger logger = Logger.getLogger(LogTest.class);
        //打印不同的日志等级
        logger.fatal("fatal");
        logger.error("error");
        logger.warn("warn");
        logger.info("info");
        logger.debug("debug");
        logger.trace("trace");
    }
}



其中还有个void setQuietMode(boolean quietMode),若是设置成true,那么LogLog中的三个日志等级都失效了!!!



六、各种Layout案例


6.1、PatternLayout(自定义格式示例)


创建过程:


①创建log4j.properties,Maven项目放置到resource目录下


# 设置rootlogger日志等级为trace、指定appender为下面定义的ConsoleAppender
log4j.rootLogger = trace,console
# 指定ConsoleAppender设置别名为console
log4j.appender.console = org.apache.log4j.ConsoleAppender
# 指定ConsoleAppender的layout设置为PatternLayout
log4j.appender.console.layout = org.apache.log4j.PatternLayout
# 设置该layout的自定义格式(解析时会调用)
log4j.appender.console.layout.ConversionPattern= [%-5p]%r %l %d{yyyy-MM-dd HH:mm:ss:SSS} %m%n


设置自定义格式时实际上会先解析出.后面的名称为ConversionPattern之后添加上set,最后通过反射调用void setConversionPattern(String conversionPattern)方法设置自定义格式。

源码查看是如何进行赋值的


经过一番努力,定位到通过反射来执行set方法的操作,看下去即可:






最终就是通过反射来执行void setConversionPattern(String conversionPattern)操作的,不仅感慨那些编写源代码的人是真的强!!!

②执行程序,输出自定义的格式内容:


public class LogTest {
    public static void main(String[] args) {
        //开启LogLog的debug模式
        LogLog.setInternalDebugging(true);
        //获取logger实例
        Logger logger = Logger.getLogger(LogTest.class);
        //打印不同的日志等级
        logger.fatal("fatal");
        logger.error("error");
        logger.warn("warn");
        logger.info("info");
        logger.debug("debug");
        logger.trace("trace");
    }
}


看框中的格式即为我们自定义的格式内容!!!


七、各种Appender示例


7.1、FileAppender及其子类


FileAppender:用于输出到文件,其有两个实现类,DailyRollingFileAppender提供了轮询功能(可根据指定时间点添加文件)、RollingFileAppender提供了根据文件大小拆分的功能。


首先看下层级图:



WriterAppender:提供属性encoding。

FileAppender:提供属性append(是否追加,默认true)、file(文件路径)、bufferedIO(布尔值,默认false)、bufferSize(文件大小,默认为8K)。

DailyRollingFileAppender:提供属性datePattern(指定间隔轮询年月日时分秒)。

RollingFileAppender:提供属性maxFileSize(单个文件最大容量)、maxBackupIndex(最大分割文件数量)。

使用任意实现类时,即可设置其父类的属性。



FileAppender示例

作用:向文件进行输出,其有两个实现类可实现轮询以及分段(多文件)。


示例演示


①创建log4j.properties


log4j.rootLogger = trace,file
# FileAppender
#  file为名称   其中属性file:文件路径   encoding:编码
log4j.appender.file = org.apache.log4j.FileAppender
log4j.appender.file.file = C:/Users/93997/Desktop/projectexers/logs/log.txt
log4j.appender.file.encoding = UTF-8
#  设置自定义布局(自定义输出格式)
log4j.appender.file.layout = org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern= [%-5p]%r %l %d{yyyy-MM-dd HH:mm:ss:SSS} %m%n


②程序测试


import org.apache.log4j.Logger;
import org.apache.log4j.helpers.LogLog;
public class LogTest {
    public static void main(String[] args) {
        //开启LogLog的debug模式
        LogLog.setInternalDebugging(true);
        //获取logger实例
        Logger logger = Logger.getLogger(LogTest.class);
        //打印不同的日志等级
        logger.fatal("fatal");
        logger.error("error");
        logger.warn("warn");
        logger.info("info");
        logger.debug("debug");
        logger.trace("trace");
    }
}




注意其中logs文件需要提前创建。


源码分析


之前我们已经通过源码看到实际赋值是通过反射调用set方法进行的,所以我们直接看其中的set方法以及默认属性即可。



说明:对于encoding编码格式的设置,是因为FileAppender继承了WriterAppender(其中有setEncoding())。



DailyRollingFileAppender示例

作用:轮询功能(根据指定是每小时,还是每天输出log日志),父类是FileAppender,包含父类的所有设置属性。


示例演示


# 日志等级为trace,指定appender为下面以roll作为别名的
log4j.rootLogger = trace,roll
# DailyRollingFileAppender 轮询
log4j.appender.roll = org.apache.log4j.DailyRollingFileAppender
log4j.appender.roll.file = /logs/log4j.log
log4j.appender.roll.encoding = UTF-8
# datePattern指的是根据分钟来进行轮询 =》可设置年月日时分秒毫秒如右: '.'yyyy-MM-dd-HH-mm-ss-SSS
log4j.appender.roll.datePattern = '.'yyyy-MM-dd-HH-mm
#  设置自定义布局(自定义输出格式)
log4j.appender.roll.layout = org.apache.log4j.PatternLayout
log4j.appender.roll.layout.ConversionPattern= [%-5p]%r %l %d{yyyy-MM-dd HH:mm:ss:SSS} %m%n


log4j.properties放置在resource目录下(Maven项目)。

这里设置路径file为/logs:指的是c:\logs目录下

测试程序:


import org.apache.log4j.Logger;
import org.apache.log4j.helpers.LogLog;
public class LogTest {
    public static void main(String[] args) {
        //开启LogLog的debug模式
        LogLog.setInternalDebugging(true);
        //获取logger实例
        Logger logger = Logger.getLogger(LogTest.class);
        //打印不同的日志等级
        logger.fatal("fatal");
        logger.error("error");
        logger.warn("warn");
        logger.info("info");
        logger.debug("debug");
        logger.trace("trace");
    }
}





上图仅作测试展示,与下方规则操作并不一致。新增的文件后缀实际上就是我们指定的每隔1分钟的时间。

规则说明(测试结果):我们指定路径为/logs/log4j.log,在第一次运行测试程序时会创建log4j.log以及其第二个文件(两个都输出内容),接着第二次运行测试程序时(间隔未满1分钟),则继续会追加到log4j.log中;第三次运行测试程序(超过1分钟),则会再次创建一个后缀添加日期的log文件并将日志内容输入到其中。


源码查看




RollingFileAppender示例

作用:按照指定文件大小进行拆分,拆分最大的文件数量可指定。其父类为FileAppender。


示例演示


# 日志等级为trace,指定appender为下面以rollfile作为别名的# 
log4j.rootLogger = trace,rollfile
# RollingFileAppender 分段
log4j.appender.rollfile = org.apache.log4j.RollingFileAppender
log4j.appender.rollfile.file = /logs/log4j.log
log4j.appender.rollfile.encoding = UTF-8
# 设置单个文件最大容量(KB、MB、GB,其他单位默认传为10MB+1)以及最大文件个数 
log4j.appender.rollfile.maxFileSize = 1MB
log4j.appender.rollfile.maxBackupIndex = 5
#  设置自定义布局(自定义输出格式)
log4j.appender.rollfile.layout = org.apache.log4j.PatternLayout
log4j.appender.rollfile.layout.ConversionPattern= [%-5p]%r %l %d{yyyy-MM-dd HH:mm:ss:SSS} %m%n


log4j.properties放置在resource目录下(Maven项目)。

其中设置单个容量大小为1MB,最大文件数为5个。

程序测试:


import org.apache.log4j.Logger;
import org.apache.log4j.helpers.LogLog;
public class LogTest {
    public static void main(String[] args) {
        //开启LogLog的debug模式
        LogLog.setInternalDebugging(true);
        //获取logger实例
        Logger logger = Logger.getLogger(LogTest.class);
        for (int i = 0; i < 1000000; i++) {
            //打印不同的日志等级
            logger.fatal("fatal");
            logger.error("error");
            logger.warn("warn");
            logger.info("info");
            logger.debug("debug");
            logger.trace("trace");
        }
}



由于程序执行1次看不到效果,所以我们执行多次来进行查看最终效果。



这些都是LogLog的debug日志,能够看到正在执行的事情。



可以看到对应的5个文件后缀名与我们设置最大文件数有关!!!

规则:若是超过文件容量maxFileSize则进行拆分,最多拆分我们设置的maxBackupIndex值数量的文件个数,若是超过文件数量则按照最先记录日志的进行覆盖。



源码分析


提问:对于最大文件容量maxFileSize可以直接写单位的吗,这么舒服?看下去吧


老样子先看下对应的set方法



接着我们分析其中的set方法:看看是如何根据单位分配的:


public class RollingFileAppender extends FileAppender {
      //默认为10MB  1maxFileSize=1字节
      protected long maxFileSize = 10*1024*1024;
      //1、设置容量方法
      public void setMaxFileSize(String value) {
        //调用了OptionConverter辅助类中的转换方法
        maxFileSize = OptionConverter.toFileSize(value, maxFileSize + 1);//见2
      }
}
public class OptionConverter {
   //2、toFileSize()根据传入的String值来转换
   public static long toFileSize(String value, long dEfault) {
        if(value == null)
          return dEfault;
        //首先将字符串中字母全都变为大写
        String s = value.trim().toUpperCase();
        //计量单位1个字节
        long multiplier = 1;
        int index;
        //下面进行容量判断,如KB、MB、GB
        if((index = s.indexOf("KB")) != -1) {
          multiplier = 1024;
          s = s.substring(0, index);//例如15KB,则为15
        }
        else if((index = s.indexOf("MB")) != -1) {
          multiplier = 1024*1024;
          s = s.substring(0, index);
        }
        else if((index = s.indexOf("GB")) != -1) {
          multiplier = 1024*1024*1024;
          s = s.substring(0, index);
        }
        if(s != null) {
          try {
             return Long.valueOf(s).longValue() * multiplier;
          }
          catch (NumberFormatException e) {
                LogLog.error("[" + s + "] is not in proper int form.");
                LogLog.error("[" + value + "] not in expected format.", e);
          }
        }
        //若是其他计量单位的话,默认返回10MB+1的容量
        return dEfault;
  }
}



通过查看源码,我们得知其中对字符串中的容量单位进行查找匹配,从而换算为指定的字节容量!!!



7.2、JDBCAppender


示例演示

概述及前提准备


JDBCAppender:这个appender能够连接数据库并且执行指定的SQL语句,主要用于将日志插入到数据库中。


提前准备如下:


①创建数据库表log:该表包含了日志的相关消息


CREATE TABLE `log` (
`log_id` int(11) NOT NULL AUTO_INCREMENT,
`project_name` varchar(255) DEFAULT NULL COMMENT '目项名',
`create_date` varchar(255) DEFAULT NULL COMMENT '创建时间',
`level` varchar(255) DEFAULT NULL COMMENT '优先级',
`category` varchar(255) DEFAULT NULL COMMENT '所在类的全名',
`file_name` varchar(255) DEFAULT NULL COMMENT '输出日志消息产生时所在的文件名称 ',
`thread_name` varchar(255) DEFAULT NULL COMMENT '日志事件的线程名',
`line` varchar(255) DEFAULT NULL COMMENT '号行',
`all_category` varchar(255) DEFAULT NULL COMMENT '日志事件的发生位置',
`message` varchar(4000) DEFAULT NULL COMMENT '输出代码中指定的消息',
PRIMARY KEY (`log_id`)
);


记得先创建一个test数据库,下面会用到

②导入Mysql的jar包(驱动包),在pom.xml中添加坐标


<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>5.1.32</version>
</dependency>



示例演示


# rootlogger的日志等级是trace,appender为JDBCAppender,logDB是下面指定的别名
log4j.rootLogger = trace,logDB
# JDBCAppender 存储到数据库中
log4j.appender.logDB=org.apache.log4j.jdbc.JDBCAppender
log4j.appender.logDB.layout=org.apache.log4j.PatternLayout
log4j.appender.logDB.Driver=com.mysql.jdbc.Driver
log4j.appender.logDB.URL=jdbc:mysql://localhost:3306/test
log4j.appender.logDB.User=root
log4j.appender.logDB.Password=123456
log4j.appender.logDB.Sql=INSERT INTO log(project_name,create_date,level,category,file_name,thread_name,line,all_category,message) values('changlu','%d{yyyy-MM-ddHH:mm:ss}','%p','%c','%F','%t','%L','%l','%m')


配置信息包含layout(输出格式)、Driver(指定mysql驱动类)、URL、User、password(连接数据库三要素)以及要执行的sql语句(其中的各种%形式都是PatternLayout中的指定内容,可见上面6.1)

SQL对应则为简单的插入语句。

测试程序:


public static void main(String[] args) {
    //开启LogLog的debug模式
    LogLog.setInternalDebugging(true);
    //获取logger实例
    Logger logger = Logger.getLogger(LogTest.class);
    for (int i = 0; i < 1000000; i++) {
        //打印不同的日志等级
        logger.fatal("fatal");
        logger.error("error");
        logger.warn("warn");
        logger.info("info");
        logger.debug("debug");
        logger.trace("trace");
    }
}



Log4j的LogLog的配置信息。



源码分析*

首先依旧是set方法查看:



那么我们会发出疑问,该类是如何执行SQL语句的呢?我们看其中的execute方法。


public class JDBCAppender extends org.apache.log4j.AppenderSkeleton
      //类名赋值操作
      public void setDriver(String driverClass) {
            try {
              //类加载我们的mysql驱动,此时进行初始化操作了
              Class.forName(driverClass);
            } catch (Exception e) {
              errorHandler.error("Failed to load driver", e,
                     ErrorCode.GENERIC_FAILURE);
            }
      }
     //获取连接操作
      protected Connection getConnection() throws SQLException {
          if (!DriverManager.getDrivers().hasMoreElements())
             setDriver("sun.jdbc.odbc.JdbcOdbcDriver");
          if (connection == null) {
            //获取数据库连接
            connection = DriverManager.getConnection(databaseURL, databaseUser,
                        databasePassword);
          }
          return connection;
      }
      //执行sql语句方法
      protected void execute(String sql) throws SQLException {
            Connection con = null;
            //这里使用到Statement来进行操作
            Statement stmt = null;
            try {
                con = getConnection();
                stmt = con.createStatement();
                //执行sql语句方法
                stmt.executeUpdate(sql);
            } finally {
                if(stmt != null) {
                    stmt.close();
                }
                closeConnection(con);
            }
            //System.out.println("Execute: " + sql);
      }
}



看了源码之后我们知道在setDriver()时就对Mysql驱动类进行了初始化,之后execute()方法中获取数据库连接,获取Statement来进行操作数据库。


舒服了,但是对于解析log4j.properties的源码部分没有进行深入,主要是对于现在的我来说太复杂了就先放着,真心觉得写源码的大佬真的太强了,自己真的还只是个菜鸟!加油吧!



八、自定义Logger


如何自定义Logger呢?依旧是在配置文件中进行配置。


语法:log4j.logger.logger_name=[level|INHERITED|NULL], appenderName, appenderName, ...。其中logger_name可以设置为指定的包名,若获取logger实例的name为这个包名及包名下的类(全限定名)即归属于该实例。

用途:通过使用自定义Logger能够将第三方包下调用的类以及自己定义的类进行日志区分,对于自己的类的日志信息输出到文件中,而对于第三方包的类输出到屏幕上。


实例演示


# rootLogger日志等级为trace,输出到屏幕上
log4j.rootLogger = trace,console
# 设置两个自定义logger
# xyz.changlu(自己创建的包)自定义logger,日志等级为info,输出到文件
log4j.logger.xyz.changlu = info,file
# 设置org.apache(第三方包)作为一个自定义logger,日志等级为error
log4j.logger.org.apache = error
# console
log4j.appender.console = org.apache.log4j.ConsoleAppender
log4j.appender.console.layout = org.apache.log4j.PatternLayout
log4j.appender.console.layout.ConversionPattern= [%-5p]%r %l %d{yyyy-MM-dd HH:mm:ss:SSS} %m%n
# FileAppender
#  file:文件路径   encoding:编码
log4j.appender.file = org.apache.log4j.FileAppender
log4j.appender.file.file = C:/Users/93997/Desktop/projectexers/logs/log.log
log4j.appender.file.encoding = UTF-8
#  设置自定义布局(自定义输出格式)
log4j.appender.file.layout = org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern= [%-5p]%r %l %d{yyyy-MM-dd HH:mm:ss:SSS} %m%n



两个自定义logger默认都会继承rootLogger的,当调用logger实例时不仅仅会调用自身的appender还会调用rootLogger的appender,并且logger实例的日志等级会改变rootLogger的日志等级(为logger实例的日志等级)。

程序测试:


import org.apache.log4j.Logger;
import org.apache.log4j.helpers.LogLog;
public class LogTest {
    public static void main(String[] args) {
        //开启LogLog的debug模式
        LogLog.setInternalDebugging(true);
        //① 自己包下类的自定义logger实例
        //getLogger()参数为xyz.changlu包下的类,所以获取到配置文件中xyz.changlu的logger实例
        //logger实例与rootLogger的日志等级都为INFO,本身实例输出到文件,rootLogger输出到窗口
        Logger logger = Logger.getLogger(LogTest.class);
        System.out.println(logger.getName());
        //打印不同的日志等级
        logger.fatal("fatal");
        logger.error("error");
        logger.warn("warn");
        logger.info("info");
        logger.debug("debug");
        logger.trace("trace");
        //② org.Apache包下的自定义logger实例,只输出到屏幕(本身实例没有设置logger)
        // 本身实例与rootLogger日志等级为error
        Logger logger1 = Logger.getLogger(Logger.class);
        System.out.println(logger1.getName());
        logger1.fatal("fatal logger1");
        logger1.error("error logger1");
        logger1.warn("warn logger1");
        logger1.info("info logger1");
        logger1.debug("debug logger1");
        logger1.trace("trace logger1");
    }
}





总结:当设置自定义logger配置时,当你设置name为一个包名时(如xyz.changlu),若在程序中调用Logger.getLogger(LogTest.class)(LogTest类的全限定类名为xyz.changlu.LogTest,即也就是logger实例的name)就是在配置文件中配置的xyz.changlulogger实例。



总结


1、Log4j是Apache提供的第三方日志框架,需要引入第三方jar包,其中同样了包含了Logger、Appender以及Layout,有六个日志等级,默认日志等级为debug。—见第一、二部分。


2、Log4j的自定义配置文件名称为log4j.xml。—见第三、四部分


3、包含了一个内置日志LogLog,需要通过LogLog.setInternalDebugging(true);来进行开启debug等级日志,作用是能够在控制台显示相关的加载配置信息过程,能够清楚其中的流程。—见第五部分


4、对于Log4j必须要对rootLogger进行初始化,默认不提供初始化,若想使用默认提供的需要调用方法BasicConfigurator.configure();初始化或者我们进行自定义配置文件见四、六、七部分,主要着重介绍输出到文件、数据库以及自定义layout的格式。—见四、六、七部分

相关实践学习
【涂鸦即艺术】基于云应用开发平台CAP部署AI实时生图绘板
【涂鸦即艺术】基于云应用开发平台CAP部署AI实时生图绘板
相关文章
|
6月前
|
监控 容灾 算法
阿里云 SLS 多云日志接入最佳实践:链路、成本与高可用性优化
本文探讨了如何高效、经济且可靠地将海外应用与基础设施日志统一采集至阿里云日志服务(SLS),解决全球化业务扩展中的关键挑战。重点介绍了高性能日志采集Agent(iLogtail/LoongCollector)在海外场景的应用,推荐使用LoongCollector以获得更优的稳定性和网络容错能力。同时分析了多种网络接入方案,包括公网直连、全球加速优化、阿里云内网及专线/CEN/VPN接入等,并提供了成本优化策略和多目标发送配置指导,帮助企业构建稳定、低成本、高可用的全球日志系统。
718 54
|
9月前
|
存储 SQL 关系型数据库
MySQL日志详解——日志分类、二进制日志bin log、回滚日志undo log、重做日志redo log
MySQL日志详解——日志分类、二进制日志bin log、回滚日志undo log、重做日志redo log、原理、写入过程;binlog与redolog区别、update语句的执行流程、两阶段提交、主从复制、三种日志的使用场景;查询日志、慢查询日志、错误日志等其他几类日志
717 35
MySQL日志详解——日志分类、二进制日志bin log、回滚日志undo log、重做日志redo log
|
8月前
|
监控 Java 应用服务中间件
Tomcat log日志解析
理解和解析Tomcat日志文件对于诊断和解决Web应用中的问题至关重要。通过分析 `catalina.out`、`localhost.log`、`localhost_access_log.*.txt`、`manager.log`和 `host-manager.log`等日志文件,可以快速定位和解决问题,确保Tomcat服务器的稳定运行。掌握这些日志解析技巧,可以显著提高运维和开发效率。
742 13
|
9月前
|
存储 缓存 关系型数据库
图解MySQL【日志】——Redo Log
Redo Log(重做日志)是数据库中用于记录数据页修改的物理日志,确保事务的持久性和一致性。其主要作用包括崩溃恢复、提高性能和保证事务一致性。Redo Log 通过先写日志的方式,在内存中缓存修改操作,并在适当时候刷入磁盘,减少随机写入带来的性能损耗。WAL(Write-Ahead Logging)技术的核心思想是先将修改操作记录到日志文件中,再择机写入磁盘,从而实现高效且安全的数据持久化。Redo Log 的持久化过程涉及 Redo Log Buffer 和不同刷盘时机的控制参数(如 `innodb_flush_log_at_trx_commit`),以平衡性能与数据安全性。
369 5
图解MySQL【日志】——Redo Log
|
8月前
|
缓存 Java 编译器
|
8月前
|
SQL 存储 关系型数据库
简单聊聊MySQL的三大日志(Redo Log、Binlog和Undo Log)各有什么区别
在MySQL数据库管理中,理解Redo Log(重做日志)、Binlog(二进制日志)和Undo Log(回滚日志)至关重要。Redo Log确保数据持久性和崩溃恢复;Binlog用于主从复制和数据恢复,记录逻辑操作;Undo Log支持事务的原子性和隔离性,实现回滚与MVCC。三者协同工作,保障事务ACID特性。文章还详细解析了日志写入流程及可能的异常情况,帮助深入理解数据库日志机制。
972 0
|
10月前
|
开发框架 运维 监控
Spring Boot中的日志框架选择
在Spring Boot开发中,日志管理至关重要。常见的日志框架有Logback、Log4j2、Java Util Logging和Slf4j。选择合适的日志框架需考虑性能、灵活性、社区支持及集成配置。本文以Logback为例,演示了如何记录不同级别的日志消息,并强调合理配置日志框架对提升系统可靠性和开发效率的重要性。
362 5
|
9月前
|
存储 关系型数据库 MySQL
图解MySQL【日志】——Undo Log
Undo Log(回滚日志)是 MySQL 中用于实现事务原子性和一致性的关键机制。在默认的自动提交模式下,MySQL 隐式开启事务,每条增删改语句都会记录到 Undo Log 中。其主要作用包括:
299 0
|
XML 安全 Java
【日志框架整合】Slf4j、Log4j、Log4j2、Logback配置模板
本文介绍了Java日志框架的基本概念和使用方法,重点讨论了SLF4J、Log4j、Logback和Log4j2之间的关系及其性能对比。SLF4J作为一个日志抽象层,允许开发者使用统一的日志接口,而Log4j、Logback和Log4j2则是具体的日志实现框架。Log4j2在性能上优于Logback,推荐在新项目中使用。文章还详细说明了如何在Spring Boot项目中配置Log4j2和Logback,以及如何使用Lombok简化日志记录。最后,提供了一些日志配置的最佳实践,包括滚动日志、统一日志格式和提高日志性能的方法。
3287 31
【日志框架整合】Slf4j、Log4j、Log4j2、Logback配置模板

热门文章

最新文章