当前位置: 首页 > news >正文

Java日志系列——概述,JUL

Java日志系列——概述,JUL

  • 日志
    • 概述
    • 日志的作用
    • 常用日志框架
  • JUL
    • 组件
    • 级别(从高到低)
    • QuickStart(控制台打印日志)
      • 解释
    • 修改打印日志的级别
      • 简单设置日志级别
      • 使用`Level.ALL`打印所有日志级别
      • 打印所有级别(解决)
        • 核心
        • 完整代码
    • 了解JUL的Handler
      • ConsoleHandler
      • FileHandler
      • MemoryHandler
      • SocketHandler
      • SLF4JBridgeHandler
    • 向文件中输出日志
    • Logger之间的父子关系
      • 自定义继承关系
      • 去除继承关系
    • JUL日志格式化
      • 方法
      • 实例
    • 自定义配置文件
      • 如何读取配置文件
        • 1.获取logManager对象
        • 2.读取配置
      • QuickStart
        • 1.在resource下放置配置文件
        • 2.设置读取配置文件
        • 3.输入日志
      • 关于配置文件
        • 指定设置单独的handler
    • Filter过滤器
    • 打印异常堆栈

日志

概述

日志文件是用于记录系统操作事件的文件集合,可分为事件日志和消息日志。具有处理历史数据、诊断问题的追踪以及理解系统的活动等重要作用。
在计算机中,日志文件是记录在操作系统或其他软件运行中发生的事件或在通信软件的不同用户之间的消息的文件。记录是保持日志的行为。在最简单的情况下,消息被写入单个日志文件。

日志的作用

  1. 调试
  2. 错误定位
  3. 数据分析

常用日志框架

  1. JUL
  2. logback
  3. log4j
  4. log4j2

JUL

JUL全称ava util Logging是java原生的日志框架,使用时不需要另外引用第三方类库,相对其他日志框架使用方便,学习简单,能够在小型应用中灵活使用。

组件

  1. Loggers:被称为记录器,应用程序通过获取Logger对象,调用其API来来发布日志信息。Logger通常时应用程序访问日志系统的入口程序。
  2. Appenders:也被称为Handlers,每个Logger都会关联一组Handlers,Logger会将日志交给关联Handlers处理,由Handlers负责将日志做记录。Handlers在此是一个抽象,其具体的实现决定了日志记录的位置可以是控制台、文件、网络上的其他日志服务或操作系统日志等。
  3. Layouts:也被称为Formatters,它负责对日志事件中的数据进行转换和格式化。Layouts决定了数据在一条日志记录中的最终形式。
  4. Level:每条日志消息都有一个关联的日志级别。该级别粗略指导了日志消息的重要性和紧迫,我可以将Level和Loggers,Appenders做关联以便于我们过滤消息。
  5. Filters:过滤器,根据需要定制哪些信息会被记录,哪些信息会被放过。

级别(从高到低)

  1. severe
  2. warning
  3. info
  4. config
  5. fine
  6. finer
  7. finest

QuickStart(控制台打印日志)

    @Test
    void contextLoads() {
        //获取logger对象
        final Logger test1 = Logger.getLogger("test1");
        //严重级别日志(最高级别)
        test1.severe("最高严重级别的日志输出");
        //警告级别日志
        test1.warning("警告类型的日志输出");
        //信息级别日志(默认级别)
        test1.info("信息级别日志输出");
        //config,配置级别日志
        test1.config("配置级别日志输出");
        //fine(没有问题的日志)
        test1.fine("没啥问题");
        //finer(比没有问题更没问题)
        test1.finer("更加没啥问题了!");
        //finest(最低级别)
        test1.finest("超级ok");
    }

在这里插入图片描述

解释

从quickstart中我们发现所有打印的级别中除了前三项以外都没有打印,也就是说从config开始的级别日志对于重要程度上比较低,所以不需要进行打印,这也是默认的配置,我们可用对默认配置进行修改
在jdk9及以上日志输出级别的配置文件在conf/logging.properties
在这里插入图片描述

修改打印日志的级别

简单设置日志级别

调用setLevel方法

final Logger test1 = Logger.getLogger("test1");
test1.setLevel(Level.FINEST);

这里我们将级别设置为FINEST但是实际上也只会打印到CONFIG为止,后续从FINE开始的都不会被打印
在这里插入图片描述

使用Level.ALL打印所有日志级别

即使我们使用.setLevel(Level.ALL)也仅能打印到CONFIG级别为止,和上面的结果是一样的!
那如何才能真正打印所有的日志级别呢(请看下面)

打印所有级别(解决)

核心

我们不仅要设置原始的Logger对象的日志级别,我们还要让Logger添加处理器(Handler)以及日志格式化器(Formatter)

        //获取logger对象
        final Logger test1 = Logger.getLogger("test1");
        //添加handler
        final ConsoleHandler consoleHandler = new ConsoleHandler();
        consoleHandler.setFormatter(new SimpleFormatter());
        test1.addHandler(consoleHandler);
        consoleHandler.setLevel(Level.ALL);
        //修改日志级别
        test1.setLevel(Level.ALL);

这里我们添加了SimpleFormatter作为我们的Formatter,添加了ConsoleHandler作为Handler,这也是JUL的默认设置的,经过我们查询就能发现
在这里插入图片描述
再设置完Handler之后我们还需要设置Handler的输出级别,因为真实处理时Handler进行处理的所以我们必须这样才能保证设置起效

完整代码

@Test
    void contextLoads() {
        //获取logger对象
        final Logger test1 = Logger.getLogger("test1");
        //添加handler
        final ConsoleHandler consoleHandler = new ConsoleHandler();
        consoleHandler.setFormatter(new SimpleFormatter());
        test1.addHandler(consoleHandler);
        consoleHandler.setLevel(Level.ALL);
        //修改日志级别
        test1.setLevel(Level.ALL);
        //严重级别日志(最高级别)
        test1.severe("最高严重级别的日志输出");
        //警告级别日志
        test1.warning("警告类型的日志输出");
        //信息级别日志(默认级别)
        test1.info("信息级别日志输出");
        //config,配置级别日志
        test1.config("配置级别日志输出");
        //fine(没有问题的日志)
        test1.fine("没啥问题");
        //finer(比没有问题更没问题)
        test1.finer("更加没啥问题了!");
        //finest(最低级别)
        test1.finest("超级ok");
    }

在这里插入图片描述

了解JUL的Handler

通过查询我们得到
在这里插入图片描述

  1. ConsoleHandler:控制台输出处理器
  2. FileHandler:文件处理器
  3. MemoryHandler:内存处理器
  4. SocketHandler:网络socket处理器
  5. SLF4JBridgeHandler:slf4j的桥梁转化处理器

ConsoleHandler

此Handler将日志记录发布到System.err 。默认情况下, SimpleFormatter用于生成简短摘要

FileHandler

简单的文件记录Handler程序。
FileHandler可以写入指定的文件,也可以写入旋转的文件集

MemoryHandler

在内存中的循环缓冲区中缓冲请求的Handler程序。
通常,此Handler只是将传入的LogRecords存储到其内存缓冲区中并丢弃早期的记录。这种缓冲非常方便并且避免了格式化成本。在某些触发条件下, MemoryHandler会将其当前缓冲区内容推送到目标Handler ,该目标通常会将它们发布到外部

SocketHandler

简单的网络日志Handler 。
LogRecords发布到网络流连接。默认情况下, XMLFormatter类用于格式化。

SLF4JBridgeHandler

将所有 JUL 日志记录桥接/路由到 SLF4J API。
本质上,这个想法是在根记录器上安装一个SLF4JBridgeHandler的实例作为系统中唯一的 JUL 处理程序。随后,SLF4JBridgeHandler 实例会将所有 JUL 日志记录重定向到基于以下级别映射的 SLF4J API:

  • FINEST -> TRACE
  • FINER -> DEBUG
  • FINE -> DEBUG
  • INFO -> INFO
  • WARNING -> WARN
  • SEVERE -> ERROR

向文件中输出日志

初始化一个FileHandler以写入给定的文件名,并带有可选的附加。
FileHandler是基于LogManager属性(或其默认值)配置的,可以写入的数据量没有限制,因此请谨慎使用。(写入过多日志会导致文件过大)

    @Test
    void test() throws IOException {
        final Logger test2 = Logger.getLogger("test2");
        /**
         * 参数
         * pattern - 输出文件的名称
         * append – 指定附加模式
         */
        final FileHandler fileHandler = new FileHandler("D:\\log_test.log", true);
        fileHandler.setFormatter(new SimpleFormatter());
        fileHandler.setLevel(Level.ALL);
        test2.setLevel(Level.ALL);
        test2.addHandler(fileHandler);
        test2.severe("严重错误");
        test2.info("信息级别日志输出");
        test2.config("配置级别日志输出");
        test2.fine("没啥问题");
    }

在这里插入图片描述

Logger之间的父子关系

JUL中Logger之间存在父子关系,这种父子关系通过树状结构存储,JUL在初始化时会创建一个顶层RootLogger作为所有Logger父Logger,存储上作为树状结构的根节点。并父子关系通过名称来关联。默认子Logger会继承父Logger的属性。

自定义继承关系

自定义的继承关系取决于你的名称的层级关系

    @Test
    void test2(){
        final Logger blog = Logger.getLogger("a.b");
        final Logger clog = Logger.getLogger("a.b.c");
        final Logger parent = clog.getParent();
        System.out.println(parent.getName());
    }

在这里插入图片描述

去除继承关系

我们使用.setUseParentHandlers(false);进行设置即可去除继承关系进行自定义设置

JUL日志格式化

我们可用通过实现Formatter自定义日志格式化的方式
做法很简单,实现Formatter接口,然后模仿SimpleFormatter写就可以了,当然我们也可以使用内部类的方式来进行实现

方法

  1. record.getLevel():返回日志级别
  2. record.getInstant() :返回时间戳(日期)
  3. record.getLoggerName() :返回日志名称
  4. record.getMessage() :返回日志信息
  5. record.getMillis() :返回时间戳(毫秒)
  6. record.getParameters() :返回日志传参
  7. record.getSourceClassName() :返回日志所在类
  8. record.getSourceMethodName():返回日志所在方法

实例

    @Test
    void test2() {
        Logger clog = Logger.getLogger("a.b.c");
        ConsoleHandler consoleHandler = new ConsoleHandler();
        consoleHandler.setFormatter(new DefineFormatter());
        consoleHandler.setLevel(Level.ALL);
        clog.setLevel(Level.ALL);
        clog.setUseParentHandlers(false);
        clog.addHandler(consoleHandler);
        clog.severe("严重的!!");
        clog.info("信息。。。。");
    }

在这里插入图片描述

自定义配置文件

如何读取配置文件

1.获取logManager对象

final LogManager logManager = LogManager.getLogManager();

2.读取配置

logManager.readConfiguration(Thread.currentThread().getContextClassLoader().getResourceAsStream("文件名"))

QuickStart

1.在resource下放置配置文件

在这里插入图片描述

handlers= java.util.logging.ConsoleHandler

.level= FINE

java.util.logging.FileHandler.pattern = %h/java%u.log
java.util.logging.FileHandler.limit = 50000
java.util.logging.FileHandler.count = 1

java.util.logging.FileHandler.maxLocks = 100
java.util.logging.FileHandler.formatter = java.util.logging.XMLFormatter


java.util.logging.ConsoleHandler.level = FINE
java.util.logging.ConsoleHandler.formatter = java.util.logging.SimpleFormatter

com.xyz.foo.level = SEVERE

2.设置读取配置文件

final LogManager logManager = LogManager.getLogManager();
//读取配置文件
logManager.readConfiguration(Thread.currentThread().getContextClassLoader().getResourceAsStream("logging.properties"));

3.输入日志

    @Test
    void test3() throws IOException {
        final LogManager logManager = LogManager.getLogManager();
        //读取配置文件
        logManager.readConfiguration(Thread.currentThread().getContextClassLoader().getResourceAsStream("logging.properties"));
        final Logger test4 = Logger.getLogger("test4");
        test4.fine("fine .....");
    }

在这里插入图片描述

关于配置文件

  1. handlers:用于指定rootLogger处理器
  2. java.util.logging.FileHandler.pattern:指定文件处理器的位置
  3. java.util.logging.FileHandler.limit :单文件大小限制
  4. java.util.logging.FileHandler.count :指定能够报错多少个日志文件
  5. java.util.logging.FileHandler.maxLocks :指定锁的数量
  6. java.util.logging.FileHandler.formatter :制定格式化器
  7. java.util.logging.ConsoleHandler.level :指定输出级别
  8. java.util.logging.FileHandler.append:指定是否追加写(true表示追加写)

指定设置单独的handler

例如我们要指定a.b.c的handler为ConsoleHandler

a.b.c.handler:java.util.logging.ConsoleHandler

当然其他单独的配置也是这样!

Filter过滤器

设置过滤器使用setFilter方法进行设置,我们需要自己进行定义实现

.setFilter(record -> {});

我们通过对LogRecord 对象用于在日志框架和各个日志处理程序之间传递日志请求。 进行自定义实现,通常来说我们会使用Filter设置个性化的实现例如设置在哪段时间内输出日志,而其他时间不输出

打印异常堆栈

对于报错信息我们应该将其异常打印出来
需要使用throwing方法进行捕获抛出
需要注意的是我们需要将级别设置为Finer!

logger.throwing("logger名称","方法名",error);

相关文章:

  • 猿创征文 |简单入门 redis6【基础命令】
  • L2-008 最长对称子串/【力扣5】 最长回文子串
  • 【Lua 入门基础篇(八)】元表
  • 创新案例分享 | 建设医院绩效管理系统,促进医院健康良性发展
  • 检查或复位状态[ feof()函数、ferror()函数和clearerr()函数 ]
  • GOLANG SLICE 切片扩容
  • 并发编程Bug起源:可见性、有序性和原子性问题
  • LastPass 开发者系统被黑已窃取源代码
  • 设计模式摘要
  • 2.Hive表结构变更时,滥用MSCK REPAIR TABLE语句,导致变更语句执行时间过长
  • [I2C]I2C通信协议详解(一) --- 什么是I2C
  • 寄——在外拼搏的你一路平安,早日团圆
  • C++11之右值引用:移动语义和完美转发(带你了解移动构造函数、纯右值、将亡值、右值引用、std::move、forward等新概念)
  • 【手把手带你学JavaSE】第八篇:抽象类和接口
  • 18年程序员生涯,读了200多本编程书,挑出一些精华分享给大家
  • 时间复杂度分析经典问题——最大子序列和
  • 【node学习】协程
  • C# 免费离线人脸识别 2.0 Demo
  • Druid 在有赞的实践
  • ECMAScript 6 学习之路 ( 四 ) String 字符串扩展
  • java2019面试题北京
  • mongo索引构建
  • Python - 闭包Closure
  • storm drpc实例
  • Vue--数据传输
  • 翻译 | 老司机带你秒懂内存管理 - 第一部(共三部)
  • 汉诺塔算法
  • 来,膜拜下android roadmap,强大的执行力
  • 前言-如何学习区块链
  • d²y/dx²; 偏导数问题 请问f1 f2是什么意思
  • 《TCP IP 详解卷1:协议》阅读笔记 - 第六章
  • Redis4.x新特性 -- 萌萌的MEMORY DOCTOR
  • 直播平台建设千万不要忘记流媒体服务器的存在 ...
  • ​Java并发新构件之Exchanger
  • ​RecSys 2022 | 面向人岗匹配的双向选择偏好建模
  • #define、const、typedef的差别
  • #LLM入门|Prompt#3.3_存储_Memory
  • #pragma multi_compile #pragma shader_feature
  • (6)添加vue-cookie
  • (NSDate) 时间 (time )比较
  • (二十四)Flask之flask-session组件
  • (六)库存超卖案例实战——使用mysql分布式锁解决“超卖”问题
  • (四)c52学习之旅-流水LED灯
  • * 论文笔记 【Wide Deep Learning for Recommender Systems】
  • .NET core 自定义过滤器 Filter 实现webapi RestFul 统一接口数据返回格式
  • .net 开发怎么实现前后端分离_前后端分离:分离式开发和一体式发布
  • .net 托管代码与非托管代码
  • .net 怎么循环得到数组里的值_关于js数组
  • .NetCore项目nginx发布
  • .NET中的Exception处理(C#)
  • .net中我喜欢的两种验证码
  • /dev/sda2 is mounted; will not make a filesystem here!
  • @Async注解的坑,小心
  • @Autowired多个相同类型bean装配问题
  • @media screen 针对不同移动设备