美文网首页
日志基础知识

日志基础知识

作者: Tinyspot | 来源:发表于2022-07-14 00:06 被阅读0次

1. 日志

  • 系统日志
  • 应用日志
  • 安全日志

2. 日志框架 vs 日志门面

  • 日志框架
    • JUL
    • Log4j
    • Logback
    • Log4j2
  • 日志门面
    • JCL
    • SLF4j
  • 时间线:log4j > JUL

2.1 JUL (Java Util Logging)

  • Java 原生日志框架
  • Logger: 日志记录器,日志系统的入口程序
  • Handler: 处理器,决定日志的输出位置,控制台或文件等; ConsoleHandler, FileHandler
  • Filter:过滤器
  • Formatter: 格式化组件
  • Level: 日志的输出级别
image.png
// Logger 之间的 ‘父子’关系,关系是通过树状结构存储的,不是 java 的 extends
// 父亲做的设置,也能同时作用于儿子
Logger logger = Logger.getLogger("org.log");
Logger logger2 = Logger.getLogger("org.log.JULTest");
System.out.println(logger2.getParent() == logger); // true
// 父亲是RootLogger,名称默认是一个空字符串
System.out.println(logger.getParent()); // java.util.logging.LogManager$RootLogger@32709393
System.out.println(logger.getParent().getName()); // 空字符串
// JUL 在初始化时会创建一个顶层RootLogger 作为所有Logger的父Logger
// RootLogger 是 LogManager的内部类
Logger logger = Logger.getLogger("org.log");
// java.util.logging.Logger#demandLogger
// JUL 日志管理器
LogManager manager = LogManager.getLogManager();
// java.util.logging.LogManager#ensureLogManagerInitialized
owner.rootLogger = owner.new RootLogger();
owner.addLogger(owner.rootLogger);
if (!owner.rootLogger.isLevelInitialized()) {
  // private final static Level defaultLevel = Level.INFO;
  owner.rootLogger.setLevel(defaultLevel);
}

/**
 * 将自定义的父子关系通过路径来进行关联
 * owner.addLogger(owner.rootLogger);
 * LoggerContext 保存节点的Map关系
 */
LoggerContext cx = getUserContext();
private final Hashtable<String,LoggerWeakRef> namedLoggers = new Hashtable<>();
//  java.util.logging - Logger
    @Test
    public void test() {
        // 不能直接new对象  Logger logger = new Logger();
        // 参数:类的全路径
        // Logger logger = Logger.getLogger("org.log.JULTest");
        Logger logger = Logger.getLogger(JULTest.class.getName());

        // 方式二
        logger.log(Level.INFO, "message");

        // 动态生成数据,用占位符
        String name = "xiao";
        int age = 20;
        logger.log(Level.INFO, "name:{0}, age:{1}", new Object[]{name, age});

        /*
         日志的级别(通过源码查看,非常简单)
              SEVERE : 错误 --- 最高级的日志级别
              WARNING : 警告
              INFO : (默认级别)消息
              CONFIG : 配置
              FINE : 详细信息(少)
              FINER : 详细信息(中)
              FINEST : 详细信息 (多) --- 最低级的日志级别
            两个特殊的级别
               OFF 可用来关闭日志记录
               ALL 启用所有消息的日志记录
            对于日志的级别,我们重点关注的是new对象的时候的第二个参数
            只展示比该数值大的日志级别
         */
    }
    @Test
    public void test() {
        Logger logger = Logger.getLogger(JULTest.class.getName());
        // 1. 关闭默认日志打印方式
        logger.setUseParentHandlers(false);
        // 2. 设置 handler 和 formatter
        ConsoleHandler handler = new ConsoleHandler();
        SimpleFormatter formatter = new SimpleFormatter();
        handler.setFormatter(formatter);
        logger.addHandler(handler);
        // 3. 设置 Level, logger 和 handler 的级别必须一致
        logger.setLevel(Level.ALL);
        handler.setLevel(Level.ALL);
        logger.info("hello");
    }
    @Test
    public void test() throws IOException {
        Logger logger = Logger.getLogger(JULTest.class.getName());
        // 1. 关闭默认日志打印方式
        logger.setUseParentHandlers(false);
        // 2. 设置 handler 和 formatter
        FileHandler fileHandler = new FileHandler("D:\\downloads\\2020.log");
        SimpleFormatter formatter = new SimpleFormatter();
        fileHandler.setFormatter(formatter);
        logger.addHandler(fileHandler);
        // 2.1 可同时添加多个 handler
        ConsoleHandler consoleHandler = new ConsoleHandler();
        consoleHandler.setFormatter(formatter);
        logger.addHandler(consoleHandler);
        // 3. 设置 Level
        logger.setLevel(Level.ALL);
        fileHandler.setLevel(Level.ALL);
        consoleHandler.setLevel(Level.CONFIG);
        logger.info("hello");
    }

2.2 Log4j

  • Logger 日志记录器
  • log4j.jar org.apache.log4j.Logger
  • Appenders 输出控制器,示例 DailyRollingFileAppender 每天输出到一个新文件
  • Layout 日志格式化
  • 主要使用其配置文件 log4j.properties
  • 8 个日志级别:ALL < TRACE < DEBUG(default) < INFO < WARN < ERROR < FATAL < OFF
  • 只输出级别不低于设定级别的日志信息

2.2.1 Logger

  • 类的全限定名,命名具有继承机制,上辈所做的属性配置会影响子辈
  • 特殊的 logger root

2.2.2 Appender 日志输出的目的地

  • ConsoleAppender
  • FileAppender
  • RollingFileAppender 按照文件大小拆分
  • DailyRollingFileAppender

2.2.3 Layouts

  • 日志格式化通过 Appenders 后面附加 Layouts 来实现
  • HTMLLayout,SimpleLayout,PatternLayout

2.2.4 PatternLayout

  • 格式化日志信息类似于 C 语言的 printf 函数
  • %p 日志级别 %n 换行
  • %m 代码里的信息
  • %L 行号
  • %c 类全名; %t 线程全名
  • %d 时间,默认为 ISO8601,也可以自定义 %d{yyyy-MM-dd HH:mm:ss:SSS}
  • % 与 字符 之间的数字用来控制宽度,示例 [%-5p] 默认右对齐,加 - 表示左对齐
# log4j.rootLogger=[level], appenderName, appenderName, ...
# log4j.rootLogger=debug,CONSOLE,FILE,ROLLING,DAILY
log4j.rootLogger=debug,CONSOLE,DAILY

log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout
log4j.appender.CONSOLE.layout.conversionPattern=[%-5p] %r %c %t %d{yyyy-MM-dd HH:mm:ss:SSS} %m%n

log4j.appender.FILE=org.apache.log4j.FileAppender
log4j.appender.FILE.layout=org.apache.log4j.PatternLayout
log4j.appender.FILE.layout.conversionPattern=[%-5p] %r %c %t %d{yyyy-MM-dd HH:mm:ss:SSS} %m%n
log4j.appender.FILE.file=/Users/xingxing.xiao/Downloads/mylog.log
# FileAppender extends WriterAppender
log4j.appender.FILE.encoding=UTF-8

# FileAppender 的子类 RollingFileAppender, DailyRollingFileAppender
log4j.appender.ROLLING=org.apache.log4j.RollingFileAppender
log4j.appender.ROLLING.layout=org.apache.log4j.PatternLayout
log4j.appender.ROLLING.layout.conversionPattern=[%-5p] %r %c %t %d{yyyy-MM-dd HH:mm:ss:SSS} %m%n
log4j.appender.ROLLING.file=/Users/xingxing.xiao/Downloads/rolling.log
log4j.appender.ROLLING.encoding=UTF-8
log4j.appender.ROLLING.maxFileSize=1MB
# 文件数量
log4j.appender.ROLLING.maxBackupIndex=5

log4j.appender.DAILY=org.apache.log4j.DailyRollingFileAppender
log4j.appender.DAILY.layout=org.apache.log4j.PatternLayout
log4j.appender.DAILY.layout.conversionPattern=[%-5p] %r %c %t %d{yyyy-MM-dd HH:mm:ss:SSS} %m%n
log4j.appender.DAILY.file=/Users/xingxing.xiao/Downloads/log.log
log4j.appender.DAILY.encoding=UTF-8
# String datePattern = "'.'yyyy-MM-dd"; 默认按天
log4j.appender.DAILY.datePattern='.'yyyy-MM-dd HH-mm-ss
private static Logger logger = Logger.getLogger(Demo2.class);
public static void main(String[] args) throws InterruptedException {
    // 加载初始化配置
    BasicConfigurator.configure();
    logger.info("242342");
}

// 源码分析:1. 创建根节点  2. 添加 Appender
static public void configure() {
    Logger root = Logger.getRootLogger();
    root.addAppender(new ConsoleAppender(
           new PatternLayout(PatternLayout.TTCC_CONVERSION_PATTERN)));
  }

Logger.getLogger(Demo2.class);
/**
* LogManager 日志管理器,静态代码块 static{}
* Loader.getResource(configurationOptionStr);
* OptionConverter.selectAndConfigure
* configurator = new PropertyConfigurator();
*/
// PropertyConfigurator
static final String  ROOT_LOGGER_PREFIX   = "log4j.rootLogger";
static final String  APPENDER_PREFIX = "log4j.appender.";

2.2.5 Log4j自定义Logger

log4j.rootLogger=debug,CONSOLE
# 自定义logger
log4j.logger.com.company=info,FILE
# 试试 配置 apache 的logger
log4j.logger.org.apache.log4j=error,FILE

log4j.appender.FILE=org.apache.log4j.FileAppender
# ......
  • rootLogger级别是 debug, 自定义logger级别是info, 日志级别以自定义logger为主
  • rootLogger输出到 console, 自定义logger输出到 file, 输出位置不同,取 rootLogger 和 自定义的并集(console 和 file 都输出了日志)
  • 打印日志时,判断父Logger 和 根Logger,无关的自定义Logger 不影响(例如 apache 的logger)

2.3 JCL

  • Jakarta Commons Logging 通用日志API
  • 本身不记录日志,也是日志门面(面向接口开发,灵活切换框架)
  • commons-logging.jar, 默认使用 JUL 日志
  • 两个基本抽象类:Log, LogFactory
private static final Log log = LogFactory.getLog(Demo2.class);
log.info("hello");
/**
* instance = this.newInstance(name);
* org.apache.commons.logging.impl.LogFactoryImpl#discoverLogImplementation
* private static final String[] classesToDiscover = new String[]{"org.apache.commons.logging.impl.Log4JLogger", "org.apache.commons.logging.impl.Jdk14Logger", "org.apache.commons.logging.impl.Jdk13LumberjackLogger", "org.apache.commons.logging.impl.SimpleLog"};
* c = Class.forName(logAdapterClassName, true, currentCL);
*/

Important

  • 日志的父子继承关系是按照包结构的关系来指定的(不是 Java 中的 extends),即越抽象的包越是父亲,越具体的包越是儿子
  • 例:按照路径做父子关系,父 org.log,子 org.log.JULTest
  • 设置 IDEA Console 控制台颜色File -> setting --> Editor --> Color Scheme --> Console Colors
  • 应用场景
    • HTTP请求的入参和结果
    • 远程接口调用情况

相关文章

网友评论

      本文标题:日志基础知识

      本文链接:https://www.haomeiwen.com/subject/zvwtirtx.html