首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >【愚公系列】2023年10月 Java教学课程 054-Logback日志框架

【愚公系列】2023年10月 Java教学课程 054-Logback日志框架

作者头像
愚公搬代码
发布2025-05-28 15:09:02
发布2025-05-28 15:09:02
16400
代码可运行
举报
文章被收录于专栏:历史专栏历史专栏
运行总次数:0
代码可运行

🚀前言

日志框架(logging framework)是一种软件模块,用于收集、存储和输出应用程序的日志信息。日志框架提供了一种标准化的方式来管理日志,使得开发者可以轻松地配置和控制日志输出。常见的日志框架包括Log4j、Logback、Java Util Logging等,它们提供了丰富的功能,如多级别日志记录、日志滚动、异步记录等。使用日志框架可以帮助开发者更好地理解应用程序的运行情况,从而更快地定位和解决问题。

🚀一、日志框架

🔎1.日志技术的概述

Java中的日志技术旨在帮助开发者更好地追踪和调试应用程序,并且是一种记录重要事件和运行时信息的重要手段。Java自带了一个日志框架,即JUL(Java Util Logging),也支持其他开源日志框架如Log4j、Logback等。

Java中的日志技术有以下优势:

  1. 标准化:Java的日志API是标准化的,因此不需要额外的库或框架就可以进行日志记录。
  2. 性能高:Java的日志系统经过了优化,可以提供高效的日志记录。
  3. 灵活度高:Java的日志系统提供了多种配置选项,使得开发者可以根据自己的需求对日志进行配置。
  4. 安全性高:Java的日志系统可以被安全地使用,因为它支持各种安全性质和机制。
  5. 可维护性高:Java的日志系统提供了一系列的机制和工具来管理和维护日志,并且也支持日志的归档和切割。

使用Java的日志技术是一种优秀的表现,能够让开发者更好地了解应用程序的运行状态,更快地定位和解决问题。

🔎2.日志技术体系结构

  • 日志规范:一些接口,提供给日志的实现框架设计的标准。
  • 日志框架:牛人或者第三方公司已经做好的日志记录实现代码,后来者直接可以拿去使用。 因为对Commons Logging的接口不满意,有人就搞了SLF4J。因为对Log4j的性能不满意,有人就搞了Logback。

🚀二、Logback日志框架

🔎1.Logback概述

Logback是Java应用程序中的一种日志框架,它是 log4j 项目的设计师 Ceki Gülcü 在他对 log4j 进行发布、出版和使用后的经验教训的基础上,设计和实现的一种日志框架。Logback 可以代替log4j框架,它不仅具有与log4j兼容的API,而且也改进了一些缺陷。与log4j相比,Logback具有更高的性能和更好的灵活性,并且可以根据不同的日志级别进行日志记录。它支持不同的输出格式,如控制台、文件、流、Syslog等。它还提供了简单的配置文件和动态日志级别更改功能,这些功能可以方便地调试应用程序和诊断问题。Logback是由Apache许可证v2.0授权的自由软件。

官方网站:https://logback.qos.ch/index.html

Logback 主要分为三个技术模块:

  1. logback-core:提供了 Logback 框架的核心功能,包括用于定义 Logback 上下文等的基础API。
  2. logback-classic:是SLF4J的一种实现,它继承了 logback-core 的基础API,同时实现了自己的日志记录器和配置器。
  3. logback-access:提供了基于 Servlet 环境的访问日志功能,可以将 Web 应用程序的访问日志记录到 Logback 中。

Logback中有三个核心组件:Logger、Appender、Layout。

  • Logger是日志记录器,是Logback中最基础的组件。我们通过Logger来记录不同的日志级别等信息。Logger可以有一个或多个父Logger,如果当前Logger没有找到适合的Appender,日志信息会向父Logger传递,直到找到适合的Appender为止。
  • Appender是日志输出器,它决定了日志信息将如何输出。常见的Appender有ConsoleAppender、FileAppender、SMTPAppender等。Logger可以有多个Appender,日志信息会同时输出到多个Appender中。
  • Layout是日志格式化器,它决定了日志信息的输出格式。常见的Layout有PatternLayout、HtmlLayout、JsonLayout等。一个Appender可以有多个Layout,每个Layout可以定义不同的日志输出格式。

Logger负责记录日志信息,Appender负责输出日志信息,Layout负责格式化输出日志信息。三个组件共同协作,实现了高效、灵活、易用的日志管理。

logback读取配置文件的顺序如下:

  1. logback-test.xml 或 logback-test.groovy (如果在classpath根目录下有logback-test.xml或logback-test.groovy文件,则加载这个文件)
  2. logback.xml 或 logback.groovy (如果在classpath根目录下有logback.xml或logback.groovy文件,则加载这个文件)
  3. logback.xml 或 logback.groovy(如果在classpath根目录下有logback.xml或logback.groovy文件,则加载这个文件)
  4. 从classpath中查找logback.xml或logback.groovy文件,如果有多个,则加载第一个找到的文件。

如果以上所有文件都不存在,则使用Logback的默认配置。

🔎2.Logback快速入门

Logback是一种灵活性高、可定制性强的日志记录框架,支持多种日志记录方式,包括控制台输出、文件输出、邮件发送等。

以下是Logback快速入门的步骤:

  1. 添加Logback依赖

在Maven项目中,可以在pom.xml中添加以下依赖:

代码语言:javascript
代码运行次数:0
运行
复制
<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-api</artifactId>
    <version>1.7.26</version>
</dependency>
<dependency>
    <groupId>ch.qos.logback</groupId>
    <artifactId>logback-core</artifactId>
    <version>1.2.3</version>
</dependency>
<dependency>
    <groupId>ch.qos.logback</groupId>
    <artifactId>logback-classic</artifactId>
    <version>1.2.3</version>
</dependency>
  1. 创建logback.xml文件

在src/main/resources目录下创建logback.xml文件,用于配置Logback的行为。

以下是一个简单的logback.xml配置文件的例子:

代码语言:javascript
代码运行次数:0
运行
复制
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <!--
        CONSOLE :表示当前的日志信息是可以输出到控制台的。
    -->
    <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
        <!--输出流对象 默认 System.out 改为 System.err-->
        <target>System.out</target>
        <encoder>
            <!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度
                %msg:日志消息,%n是换行符-->
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%-5level]  %c [%thread] : %msg%n</pattern>
        </encoder>
    </appender>

    <!-- File是输出的方向通向文件的 -->
    <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <encoder>
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
            <charset>utf-8</charset>
        </encoder>
        <!--日志输出路径-->
        <file>C:/code/itheima-dlei-data.log</file>
        <!--指定日志文件拆分和压缩规则-->
        <rollingPolicy
                class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
            <!--通过指定压缩文件名称,来确定分割文件方式-->
            <fileNamePattern>C:/code/itheima-data2-%d{yyyy-MMdd}.log%i.gz</fileNamePattern>
            <!--文件拆分大小-->
            <maxFileSize>1MB</maxFileSize>
        </rollingPolicy>
    </appender>

    <!--

    level:用来设置打印级别,大小写无关:TRACE, DEBUG, INFO, WARN, ERROR, ALL 和 OFF
   , 默认debug
    <root>可以包含零个或多个<appender-ref>元素,标识这个输出位置将会被本日志级别控制。
    -->
    <root level="all">
        <appender-ref ref="CONSOLE"/>
        <appender-ref ref="FILE" />
    </root>
</configuration>

这个配置文件定义了一个名为"STDOUT"的控制台输出appender,使用一个pattern定义了输出格式,并将它附加到了根logger上。

  1. 在代码中使用Logback

在代码中使用Logback非常简单,只需创建一个Logger实例即可。例如:

代码语言:javascript
代码运行次数:0
运行
复制
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class MyClass {
    private static final Logger LOGGER = LoggerFactory.getLogger(MyClass.class);

    public void doSomething() {
        LOGGER.debug("Some debug message.");
        LOGGER.info("Some info message.");
        LOGGER.warn("Some warning message.");
        LOGGER.error("Some error message.");
    }
}

上述代码中,通过org.slf4j.LoggerFactory类获取Logger实例,然后可以使用debug()、info()、warn()和error()方法记录日志。

  1. 运行代码并查看日志

现在,可以运行代码,并查看输出结果。在控制台上,应该会看到类似下面的输出:

代码语言:javascript
代码运行次数:0
运行
复制
11:08:21.136 [main] DEBUG MyClass - Some debug message.
11:08:21.136 [main] INFO  MyClass - Some info message.
11:08:21.136 [main] WARN  MyClass - Some warning message.
11:08:21.136 [main] ERROR MyClass - Some error message.

在实际的项目中,还可以结合使用Logback的其他功能,如异步输出、动态配置等。

🔎3.Logback配置详解

Logback是一款可扩展的日志框架,允许以非常灵活的方式管理日志记录。下面是Logback的配置详解:

  1. 配置文件名

Logback会自动查找并加载名为“logback.xml”或“logback.groovy”的配置文件,如果没有找到这些文件,则会使用默认配置。

  1. 配置文件结构

Logback的配置文件结构分为三个部分:configuration、appender、logger。其中,configuration定义了整个配置文件的根节点;appender定义了日志输出的目的地;logger定义了日志记录器及其输出级别等信息。

  1. 配置文件示例

下面是一个较为完整的Logback配置文件示例:

代码语言:javascript
代码运行次数:0
运行
复制
<?xml version="1.0" encoding="UTF-8"?>
<configuration debug="false">

  <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
    <encoder>
      <pattern>%-5level [%thread] %logger - %msg%n</pattern>
    </encoder>
  </appender>

  <appender name="FILE" class="ch.qos.logback.core.FileAppender">
    <file>/var/log/myapp/myapp.log</file>
    <encoder>
      <pattern>%date %level [%thread] %logger - %msg%n</pattern>
    </encoder>
  </appender>

  <logger name="com.mycompany.myapp" level="DEBUG">
    <appender-ref ref="STDOUT" />
    <appender-ref ref="FILE" />
  </logger>

  <root level="INFO">
    <appender-ref ref="STDOUT" />
    <appender-ref ref="FILE" />
  </root>

</configuration>
  1. 其他常用配置项

(1)日志级别控制:

Logback支持5种日志级别:TRACE、DEBUG、INFO、WARN、ERROR。可以通过logger节点的level属性来设置日志记录器的级别,也可以在root节点中设置默认日志级别。

(2)日志格式控制:

可以通过encoder节点来设置日志的输出格式,常用的占位符有:%date、%level、%logger、%msg等。

(3)日志输出控制:

可以通过appender节点来配置日志的输出方式,包括文件输出、控制台输出等。

(4)日志分割:

可以通过TimeBasedRollingPolicy来设置日志的按时间分割,即每天/每小时/每分钟生成一个新的日志文件。

(5)异步日志:

可以通过AsyncAppender来实现异步输出日志,提高程序的性能。

以上是Logback配置的一些常用配置项,可以根据实际需求进行设置。

🔎4.案例

代码语言:javascript
代码运行次数:0
运行
复制
package com.itheima;

import java.text.SimpleDateFormat;
import java.util.Date;

/**
   商品(封装属性信息)
 */
public class Article {
    private String name;
    private double price;
    private String type;
    private int storage;
    private String desc;
    private Date createDate; // 上架时间

    public Article(){

    }

    public Article(String name, double price, String type, int storage, String desc, Date createDate) {
        this.name = name;
        this.price = price;
        this.type = type;
        this.storage = storage;
        this.desc = desc;
        this.createDate = createDate;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public double getPrice() {
        return price;
    }

    public void setPrice(double price) {
        this.price = price;
    }

    public String getType() {
        return type;
    }

    public void setType(String type) {
        this.type = type;
    }

    public int getStorage() {
        return storage;
    }

    public void setStorage(int storage) {
        this.storage = storage;
    }

    public String getDesc() {
        return desc;
    }

    public void setDesc(String desc) {
        this.desc = desc;
    }

    public String getCreateDate() {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss EEE a");
        return sdf.format(createDate);
    }

    public void setCreateDate(Date createDate) {
        this.createDate = createDate;
    }
}
代码语言:javascript
代码运行次数:0
运行
复制
package com.itheima;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.*;

/**
     需求:商品管理系统的模拟开发。
 */
public class ArticleManagerSystem {
    /**
       1、定义一个静态的Map集合存储全部店家和其商品橱柜
     */
    public static Map<String, List<Article>> allArticles = new HashMap<>();

    /**
       3、静态代码块初始化一些测试数据
     */
    static {
        // 创建商家对象的橱柜
        List<Article> articles1 = new ArrayList<>();
        articles1.add(new Article("《干就对了-Java入门》", 100.5,"书籍",1000000,"作者:Dlei", new Date()));
        articles1.add(new Article("《MySQL避免删库到跑路》", 9.9,"书籍",10,"作者:阿毛", new Date()));
        allArticles.put("图书直营店", articles1);

        List<Article> articles2 = new ArrayList<>();
        articles2.add(new Article("育发液", 10.5,"药品",11000,"秃顶必备", new Date()));
        articles2.add(new Article("防脱液", 19.9,"药品",110,"每天脱发100根就要用", new Date()));
        allArticles.put("生发专营店", articles2);
    }

    /**
       2、定义日志对象
     */
    public static Logger logger = LoggerFactory.getLogger(ArticleManagerSystem.class);

    public static Scanner sysSc = new Scanner(System.in);

    public static void main(String[] args) {
        logger.debug("有人进入系统~~");
        while (true) {
            System.out.println("=============欢迎进入商城=============");
            System.out.println("1、查询全部商品信息");
            System.out.println("2、上架商品");
            System.out.println("3、下架商品");
            System.out.println("4、修改商品");
            System.out.println("5、根据条件查询商品");
            System.out.println("6、退出系统");
            System.out.println("请您输入操作的命令:");
            int command = sysSc.nextInt();
            switch (command) {
                case 1:
                     // 查询商品信息(独立功能独立成方法)
                    showAllArticles();
                    break;
                case 2:
                    // 上架商品
                    addArticle();
                    break;
                case 3:
                    // 下架商品
                    deleteArticle();
                    break;
                case 4:
                    // 修改商品信息
                    break;
                case 5:
                    // 根据条件查询商品信息
                    break;
                case 6:
                    // 退出系统
                    System.out.println("欢迎下次再来哦~~");
                    return;
                default:
                    System.out.println("您输入的命令有毛病~~");
            }
        }
    }

    /**
       商品下架:Map<String, List<Article>> allArticles = {店家名=[a1,a2] , 店家名2=[a1,a2] , 新店铺=[a1],...}
     */
    public static void deleteArticle() {
        System.out.println("===================下架商品======================");
        // 1、判断是否有商品存在。
        if(allArticles.size() == 0){
            System.out.println("当前系统没有任何商品,不能下架了!");
            return;
        }

        while (true) {
            // 2、存在商品需要下架。
            System.out.println("请您输入店铺名称:");
            String storeName = sysSc.next();

            // 2、判断这个店铺是否存在,根据店铺找橱柜。
            List<Article> articles = allArticles.get(storeName);
            if(articles != null) {
                // 店铺存在,橱柜拿到了
                // 3、请输入的商品名称,根据商品名称查询该店铺的该商品对象。再删除它
                while (true) {
                    System.out.println("请您输入商品名称:");
                    String name = sysSc.next();
                    Article article = getArticleByName(articles,name);
                    // 4、判断这个商品对象是否存在
                    if(article != null){
                        // 定位到需要下架的商品对象,删除它
                        articles.remove(article);
                        System.out.println("下架成功~~~");
                        return;
                    }else {
                        System.out.println("您在当前店家下没有找到该商品,不存在该商品名称~~");
                    }
                }
            }else {
               // 店铺不存在,没有这个橱柜
               System.out.println("您输入的店铺压根没有~~~");
            }
        }
    }

    /**
      去某个橱柜下,找出某个商品对象
     * @param articles
     * @param name
     * @return
     */
    public static Article getArticleByName(List<Article> articles, String name){
        for (Article article : articles) {
            if(article.getName().equals(name)) {
                return article;
            }
        }
        return null;
    }

    /**
       添加商品信息:上架商品  Map<String, List<Article>> allArticles = {店家名=[a1,a2] , 店家名2=[a1,a2] , 新店铺=[]...}
     */
    public static void addArticle() {
        System.out.println("===================展示系统全部商品信息======================");
        // 1、请您输入店铺名称
        System.out.println("请您输入店铺名称:");
        String storeName = sysSc.next();

        List<Article> articles = null; // 先定义一个变量用于后期指向橱柜
        // 2、判断这个店铺是否存在
        if(allArticles.containsKey(storeName)) {
            // 店铺已经存在,获取其橱柜
            articles = allArticles.get(storeName);
        }else {
            // 这是一个新店铺,为它创建一个新橱柜
            articles = new ArrayList<>();
            // 新店铺要加入到系统中去
            allArticles.put(storeName, articles);
        }

        // 3、创建一个新的商品对象封装数据
        Article article = new Article();
        System.out.println("请您输入商品名称:");
        String name = sysSc.next();
        article.setName(name);

        while (true) {
            Scanner sc = new Scanner(System.in);
            try {
                System.out.println("请您输入商品的价格:");
                double price = sc.nextDouble();
                if(price >= 0){
                    article.setPrice(price);
                    break;
                }else {
                    System.out.println("价格必须是正数~~");
                }
            } catch (Exception e) {
                System.out.println("价格数据不可以随便写,必须是数值~~");
            }
        }

        System.out.println("请您输入商品类型:");
        String type = sysSc.next();
        article.setType(type);

        System.out.println("请您输入商品描述:");
        String desc = sysSc.next();
        article.setDesc(desc);

        while (true) {
            Scanner sc = new Scanner(System.in);
            try {
                System.out.println("请您输入商品的库存:");
                int storage = sc.nextInt();
                if(storage >= 0){
                    article.setStorage(storage);
                    break;
                }else {
                    System.out.println("库存必须是正数~~");
                }
            } catch (Exception e) {
                System.out.println("库存数据不可以随便写,必须是数值~~");
            }
        }

        // 上架时间
        article.setCreateDate(new Date());

        // 5、把商品对象加入到橱柜
        articles.add(article);
        System.out.println("恭喜你,商品上架成功了~~");
    }

    /**
       展示商品  Map<String, List<Article>> allArticles = {店家名=[a1,a2] , ...}
     */
    public static void showAllArticles() {
        System.out.println("===================展示系统全部商品信息======================");
        allArticles.forEach((name, articles) -> {
            System.out.println("店铺:" + name);
            for (Article article : articles) {
                System.out.println("\t\t商品名称:" + article.getName());
                System.out.println("\t\t商品价格:" + article.getPrice());
                System.out.println("\t\t商品类型:" + article.getType());
                System.out.println("\t\t商品库存:" + article.getStorage());
                System.out.println("\t\t商品描述:" + article.getDesc());
                System.out.println("\t\t商品上架时间:" + article.getCreateDate());
                System.out.println("\t\t---------------------------");
            }
        });
    }
}
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2023-10-14,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 🚀前言
  • 🚀一、日志框架
    • 🔎1.日志技术的概述
    • 🔎2.日志技术体系结构
  • 🚀二、Logback日志框架
    • 🔎1.Logback概述
    • 🔎2.Logback快速入门
    • 🔎3.Logback配置详解
    • 🔎4.案例
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档