springboot日志使用 SLF4J+Logback 实现(springboot默认的日志实现),日志打印到控制台及日志输出到指定文件

还是直接上代码

@Slf4j 这玩意 默认支持 不用引入

yml 配置文件

# 日志配置  如果配置了xml 这个就不生效了 xml优先级最高
#logging:
#  file:
#    path: /home/logs  # 日志目录地址
#    name:  /home/logs/skeleton.log
#    max-size: 1KB  # 设置日志大小的最大大小 1KB 用于演示 单位包括 KB、MB、GB
#    max-history: 3  # 默认存储最近7
#    total-size-cap: 3KB  #日志文档的总大小:当日志文档总大小超过该阈值会删除备份
#  level:
#    root: info  #全局的日志等级 哪些日志输出

下面分享 xml 方式
在 资源目录下创建 logback-spring.xml 粘贴走 即可 重启 看控制台变化 还有磁盘 有没有写入

坑 :
我在创建的时候 发现 xml 没有生效 排查了半天 发现 在创建 logback-spring.xml 这个文件的时候
我不是手打的 是复制的 文件名 前面多了个空格 导致不生效
所以如果有小伙伴 和我一样 复制的文件名 一定要小心
文件名两边不要复制多了 空格

<?xml version="1.0" encoding="UTF-8"?>
<configuration  scan="true" scanPeriod="10 seconds">
    <!-- 日志级别从低到高分为TRACE < DEBUG < INFO < WARN < ERROR < FATAL,如果设置为WARN,则低于WARN的信息都不会输出 -->
    <!-- scan:当此属性设置为true时,配置文件如果发生改变,将会被重新加载,默认值为true -->
    <!-- scanPeriod:设置监测配置文件是否有修改的时间间隔,如果没有给出时间单位,默认单位是毫秒。当scan为true时,此属性生效。默认的时间间隔为1分钟。 -->
    <!-- debug:当此属性设置为true时,将打印出logback内部日志信息,实时查看logback运行状态。默认值为false。 -->

    <contextName>logback</contextName>
    <!-- name的值是变量的名称,value的值时变量定义的值。通过定义的值会被插入到logger上下文中。定义变量后,可以使“${}”来使用变量。 -->
    <!--    日志输出位置-->
    <property name="log.path" value="/home/logs/xx-skeleton" />
<!--    按照日期一个文件夹-->
    <timestamp key="datetime" datePattern="yyyy-MM-dd"/>

    <!-- 彩色日志 -->
    <!-- 配置格式变量:CONSOLE_LOG_PATTERN 彩色日志格式 -->
    <!-- magenta:洋红 -->
    <!-- boldMagenta:粗红-->
    <!-- cyan:青色 -->
    <!-- white:白色 -->
    <!-- magenta:洋红 -->
    <property name="CONSOLE_LOG_PATTERN"
              value="%yellow(%date{yyyy-MM-dd HH:mm:ss}) |%highlight(%-5level) |%blue(%thread) |%blue(%file:%line) |%green(%logger) |%cyan(%msg%n)"/>


    <!--输出到控制台-->
    <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
        <!--此日志appender是为开发使用,只配置最底级别,控制台输出的日志级别是大于或等于此级别的日志信息-->
        <!-- 例如:如果此处配置了INFO级别,则后面其他位置即使配置了DEBUG级别的日志,也不会被输出 -->
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <level>INFO</level>
        </filter>
        <encoder>
            <Pattern>${CONSOLE_LOG_PATTERN}</Pattern>
            <!-- 设置字符集 -->
            <charset>UTF-8</charset>
        </encoder>
    </appender>


    <!--输出到文件-->

    <!-- 时间滚动输出 level为 INFO 日志 -->
    <appender name="INFO_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <!-- 正在记录的日志文件的路径及文件名 -->
        <file>${log.path}/${datetime}/log_info.log</file>
        <!--日志文件输出格式-->
        <encoder>
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
            <charset>UTF-8</charset>
        </encoder>
        <!-- 日志记录器的滚动策略,按日期,按大小记录 -->
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <!-- 每天日志归档路径以及格式 -->
            <fileNamePattern>${log.path}/${datetime}/info/log-info-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
            <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                <maxFileSize>100MB</maxFileSize>
            </timeBasedFileNamingAndTriggeringPolicy>
            <!--日志文件保留天数-->
            <maxHistory>7</maxHistory>
        </rollingPolicy>
        <!-- 此日志文件只记录info级别的 -->
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>INFO</level>
            <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>
    </appender>

    <!-- 时间滚动输出 level为 WARN 日志 -->
    <appender name="WARN_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <!-- 正在记录的日志文件的路径及文件名 -->
        <file>${log.path}/${datetime}/log_warn.log</file>
        <!--日志文件输出格式-->
        <encoder>
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
            <charset>UTF-8</charset> <!-- 此处设置字符集 -->
        </encoder>
        <!-- 日志记录器的滚动策略,按日期,按大小记录 -->
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <fileNamePattern>${log.path}/${datetime}/warn/log-warn-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
            <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                <maxFileSize>100MB</maxFileSize>
            </timeBasedFileNamingAndTriggeringPolicy>
            <!--日志文件保留天数-->
            <maxHistory>7</maxHistory>
        </rollingPolicy>
        <!-- 此日志文件只记录warn级别的 -->
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>warn</level>
            <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>
    </appender>


    <!-- 时间滚动输出 level为 ERROR 日志 -->
    <appender name="ERROR_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <!-- 正在记录的日志文件的路径及文件名 -->
        <file>${log.path}/${datetime}/log_error.log</file>
        <!--日志文件输出格式-->
        <encoder>
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
            <charset>UTF-8</charset> <!-- 此处设置字符集 -->
        </encoder>
        <!-- 日志记录器的滚动策略,按日期,按大小记录 -->
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <fileNamePattern>${log.path}/${datetime}/error/log-error-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
            <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                <maxFileSize>100MB</maxFileSize>
            </timeBasedFileNamingAndTriggeringPolicy>
            <!--日志文件保留天数-->
            <maxHistory>7</maxHistory>
        </rollingPolicy>
        <!-- 此日志文件只记录ERROR级别的 -->
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>ERROR</level>
            <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>
    </appender>

    <!--
        <logger>用来设置某一个包或者具体的某一个类的日志打印级别、以及指定<appender>。
        <logger>仅有一个name属性,
        一个可选的level和一个可选的addtivity属性。
        name:用来指定受此logger约束的某一个包或者具体的某一个类。
        level:用来设置打印级别,大小写无关:TRACE, DEBUG, INFO, WARN, ERROR, ALL 和 OFF,
              如果未设置此属性,那么当前logger将会继承上级的级别。
    -->
    <!--
        使用mybatis的时候,sql语句是debug下才会打印,而这里我们只配置了info,所以想要查看sql语句的话,有以下两种操作:
        第一种把<root level="INFO">改成<root level="DEBUG">这样就会打印sql,不过这样日志那边会出现很多其他消息
        第二种就是单独给mapper下目录配置DEBUG模式,代码如下,这样配置sql语句会打印,其他还是正常DEBUG级别:
     -->
    <!--开发环境:打印控制台-->
    <springProfile name="dev">
        <!--可以输出项目中的debug日志,包括mybatis的sql日志-->
        <logger name="com.xx" level="INFO" />

        <!--
            root节点是必选节点,用来指定最基础的日志输出级别,只有一个level属性
            level:用来设置打印级别,大小写无关:TRACE, DEBUG, INFO, WARN, ERROR, ALL 和 OFF,默认是DEBUG
            可以包含零个或多个appender元素。
        -->
        <root level="INFO">
            <appender-ref ref="CONSOLE" />
            <appender-ref ref="INFO_FILE" />
            <appender-ref ref="WARN_FILE" />
            <appender-ref ref="ERROR_FILE" />
        </root>
    </springProfile>


    <!--生产环境:输出到文件-->
    <springProfile name="prd">

        <root level="INFO">
            <appender-ref ref="CONSOLE" />
            <appender-ref ref="DEBUG_FILE" />
            <appender-ref ref="INFO_FILE" />
            <appender-ref ref="ERROR_FILE" />
            <appender-ref ref="WARN_FILE" />
        </root>
    </springProfile>

</configuration>

测试

@RestController
@RequestMapping("/test-cg")
@Slf4j
public class TestCgController extends BaseController {
    @GetMapping("index14")
    @ApiOperation(value = "日志测试")
    @PassToken
    public R index14(){
        log.trace("我是trace");
        log.debug("我是 debug");
        log.info("我是info");
        log.warn("我是warn");
        log.error("我是error");
        return R.success();
    }
}

最后再送 一个 定时任务 删除过期 日志文件 防止删除失败

定时任务 用的 xxl-job 不太清除这个定时任务插件 可百度

package com.xxx.init.job;

import com.xxx.api.out.R;
import com.xxx.init.aop.XxlJobTask;
import com.xxx.init.utils.BaseDataUtil;

import com.xxl.job.core.handler.annotation.XxlJob;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;


import java.nio.file.*;

import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;

import java.util.List;

/**
 * User:Json
 * Date: 2024/4/18
 **/
@Slf4j
@Component
public class RuntimeFileClearJob {

    @Value("${spring.application.name}")
    private String serviceName;

    private static final String LOG_DIRECTORY_WINDOWS = "home\\logs"; // Windows系统的日志目录
    private static final String LOG_DIRECTORY_LINUX = "/home/logs/"; // Linux系统的日志目录


    //jobHandler 必须唯一  每天凌晨3点13分0秒触发 0 13 3 * * ?
    @XxlJob("planRuntimeFileClearJava")
    @XxlJobTask(jobDesc = "日志文件的清空-Java", cron = "0 13 3 * * ?", jobHandler = "planRuntimeFileClearJava", routeStrategy = "ROUND")
    //自定义注解
    public R planRuntimeFileClearJava() {
        Integer clearCacheDay = BaseDataUtil.getSystemConfigNacos().getClearCacheDay();
        log.info("===========清空缓存日志文件开始执行==========");
        if (clearCacheDay == null) {
            //从nacos里读,读不到就设置为7天。
            clearCacheDay = 7;
        }
        cleanupLogs(clearCacheDay);
        log.info("===========清空缓存日志文件结束执行==========");
        return R.success();
    }


    public void cleanupLogs(Integer clearCacheDay) {
        String logDirectory = getLogDirectory();
        if (logDirectory == null) {
            log.error("日志文件 目录不能为空!");
            return;
        }

        List<String> oldFolders = getOldFolders(logDirectory, clearCacheDay);
        if (!CollectionUtils.isEmpty(oldFolders)) {
            deleteOldFolders(oldFolders);
        }

    }

    //获取日志根目录
    private String getLogDirectory() {
        // 根据运行环境确定日志目录
        String osName = System.getProperty("os.name").toLowerCase();
        if (osName.contains("windows")) {
            String drive = Paths.get("").toAbsolutePath().getRoot().toString();
            return drive + "\\" + LOG_DIRECTORY_WINDOWS + "\\" + serviceName;
        } else {
            return LOG_DIRECTORY_LINUX + "/" + serviceName;
        }
    }

    //获取过期文件夹 不会递归着找 只会找当前目录下的  文件夹格式是 : 2024-04-18 会根据文件夹检索
    private List<String> getOldFolders(String logDirectory, Integer clearCacheDay) {
        List<String> oldFolders = new ArrayList<>();
        LocalDate today = LocalDate.now();
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");

        try {
            Files.list(Paths.get(logDirectory))
                    .filter(Files::isDirectory)
                    .forEach(dir -> {
                        String dirName = dir.getFileName().toString();
                        try {
                            LocalDate folderDate = LocalDate.parse(dirName, formatter);
                            if (folderDate.isBefore(today.minusDays(clearCacheDay))) {
                                oldFolders.add(dir.toString());
                            }
                        } catch (Exception e) {
                            // Ignore non-date directories
                            log.error("获取过期文件夹报错:" + e.getMessage());
                        }
                    });
        } catch (Exception e) {
            e.printStackTrace();
        }

        return oldFolders;
    }


    //删除过期文件夹  linux 注意 jar是否有 删除文件夹的权限 未测 linux
    private void deleteOldFolders(List<String> oldFolders) {
        oldFolders.forEach(folder -> {
            try {
                Files.walk(Paths.get(folder))
                        .sorted((path1, path2) -> -path1.compareTo(path2))
                        .forEach(path -> {
                            try {
                                Files.deleteIfExists(path);
                            } catch (Exception e) {
                                e.printStackTrace();
                            }
                        });
            } catch (Exception e) {
                e.printStackTrace();
                log.error("删除过期文件夹报错:" + e.getMessage());
            }
        });
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/556530.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

FlinkCDC基础篇章2-数据源 SqlServerCDC写入到ES中

接着 上期FlinkCDC基础篇章1-安装使用 下载 Flink 和所需要的依赖包 # 下载 Flink 1.17.0 并将其解压至目录 flink-1.17.0 下载下面列出的依赖包&#xff0c;并将它们放到目录 flink-1.17.0/lib/ 下&#xff1a; 下载链接只对已发布的版本有效, SNAPSHOT 版本需要本地编译 …

视频批量高效剪辑,轻松翻转视频画面,支持将视频画面进行逆时针90度翻转。

在视频编辑的海洋中&#xff0c;你是否曾遇到过需要批量翻转视频画面的情况&#xff1f;传统的视频编辑工具在面对这样的需求时&#xff0c;往往显得力不从心&#xff0c;效率低下。今天&#xff0c;我要为大家介绍一款全新的视频编辑神器&#xff0c;它将彻底改变你的视频编辑…

小试牛刀!

1.从双倍数组中还原原数组&#xff08;力扣&#xff0c;vector&#xff09; java式c解法。 class Solution { public:vector<int> findOriginalArray(vector<int>& changed) {int n changed.size();if(n % 2 1) return {};map<int, int> mp;for(int c…

【最新可用】Claude国内镜像,可上传图片,可用Claude3全系模型,包括Pro版本的Opus),亲测比GPT好用

Claude对话、上传图片的超详细教程来啦&#xff01; 近期&#xff0c;Claude 3 Opus的发布引发了网络上的广泛关注与热议&#xff0c;有观点认为其性能已经凌驾于GPT-4之上。虽然网络上已经出现了大量基于这两款先进AI技术的实际应用案例&#xff0c;但仍有许多人对在国内如何…

游戏生成式 AI:编织梦想,避开阴影

想象一下&#xff0c;一个沉浸式的游戏世界中玩家遇到的每个 NPC 都由 AI 驱动&#xff0c;他们能与玩家进行互动&#xff0c;从改变游戏体验。据 Inword 一项研究显示&#xff0c;绝大多数游戏玩家渴望这种互动&#xff0c;愿意投入更多的时间和金钱来玩这种由 AI 驱动的游戏。…

网络编程套接字(三)之TCP服务器简单实现

目录 一、服务端TcpServer 1、tcp_server.hpp 2、tcp_server.cc 二、客户端TcpClient tcp_client.cc 三、服务器和客户端进行通信 四、完整代码 一、服务端TcpServer 首先我们需要对服务端进行封装。我们需要的成员变量有IP地址&#xff0c;端口号port&#xff0c;以及监…

JMM与内存屏障

一、cpu多核并发缓存架构解析 JMM内存模型&#xff1a;java多线程内存模型跟cpu缓存模型类似&#xff0c;是基于cpu缓存模型来建立的&#xff0c;java线程内存模型是标准化的&#xff0c;屏蔽掉了底层不同计算机的区别 JMM数据原子操作 read(读取)&#xff1a;从主内存读取数据…

作为Boss,还在写代码。what?赶紧改掉这个坏毛病

有些创业中的老板&#xff0c;经常或者偶尔也要写代码&#xff0c;我听了很震惊呀&#xff0c;这叫创业吗&#xff1f;这不是给员工打工吗&#xff1f;其他重要的事情谁来干&#xff0c;这个毛病一定要改。 一、比起写代码&#xff0c;你还有更重要的事情要做 作为BOSS和创业…

【Node.js从基础到高级运用】二十五、Node.js中Cluster的作用

引言 Node.js中的cluster模块允许您轻松创建共享服务器端口的子进程。这是一个核心模块&#xff0c;用于在Node.js应用程序中实现多进程架构&#xff0c;以充分利用多核CPU系统的计算能力。 cluster介绍 当您启动一个Node.js应用程序时&#xff0c;默认情况下它运行在单个进程…

怎么设置启用远程桌面? 如何让外网电脑远程本地内网?

如何远程控制电脑&#xff1f;最简单实用的方案是开启电脑系统自带的远程桌面功能&#xff0c;如果涉及跨网、内外网互通&#xff0c;可以同时用快解析内网映射外网。下面是方案的具体实施步骤&#xff0c;供大家参考。 怎么打开设置启用远程桌面&#xff1f; 1.在目标需要远…

idea 中导入的项目maven不自动下载依赖包

导入之后不会自动引入依赖包&#xff0c;如下图&#xff0c;external libraries 下没有依赖 解决方案&#xff1a;重新更新下maven的Local repository 即可

实测52.4MB/s!全志T3+FPGA的CSI通信案例分享!

CSI总线介绍与优势 CSI&#xff08;CMOS sensor parallel interfaces&#xff09;总线是一种用于连接图像传感器和处理器的并行通信接口&#xff0c;应用于工业自动化、能源电力、智慧医疗等领域&#xff0c;CSI总线接口示意图如下所示&#xff08;以全志科技T3处理器的CSI0为…

Qt实现Mysql数据库的连接,查询,修改,删除,增加功能

Qt实现Mysql数据库的连接&#xff0c;查询&#xff0c;修改&#xff0c;删除&#xff0c;增加功能 安装Mysql数据库&#xff0c;QtCreator Mysql选择Mysql Server 8.1版本安装。 Mysql Server 8.1安装过程 1.首先添加网络服务权限&#xff1a; WinR键输入compmgmt.msc进入…

密码学 | 数字签名 + 数字证书

&#x1f951;原文&#xff1a;数字签名和数字证书的原理解读 - 知乎 &#x1f951;声明&#xff1a;后文图中若未明确指明&#xff0c;默认是 Bob 的公钥或私钥。 Step1&#xff1a;Bob 有两把钥匙&#xff0c;一把是公钥&#xff0c;另一把是私钥。 Step2&#xff1a;Bob 把…

安全狗云眼的主要功能有哪些?

"安全狗云眼"是一款综合性的网络安全产品&#xff0c;主要用于实时监控和保护企业的网络安全。其核心功能包括威胁检测、漏洞扫描、日志管理和合规性检查等。 以下是安全狗云眼的主要功能详细介绍&#xff1a; 1、资产管理 定期获取并记录主机上的Web站点、Web容器、…

达梦数据库——异常崩溃(core)分析处理

CORE文件介绍 core文件是在程序异常崩溃时生成的文件&#xff0c;它包含了程序在崩溃瞬间的内存状态信息&#xff0c;主要是用来调试和分析问题。我们可以使用调试器工具&#xff08;如GDB&#xff09;来分析core文件&#xff0c;以便定位和解决问题。 CORE文件的配置 开启cor…

ActiveMQ主从架构和集群架构的介绍及搭建

目录 一、主从和集群架构的特点 1.1 主从架构的-Master/slave模式特点 1.2 集群架构-Cluster模式特点 二、ActiveMQ的主从架构 2.1 架构图 2.2 特点 2.3 实现方式&#xff08;3种&#xff09; 2.4 实现 &#xff08;基于LevelDB复制&#xff09; 2.4.1 准备环境 2.4.2…

2024化工制造企业数字化白皮书

来源&#xff1a;蓝凌研究院 中国石油和化学工业联合会发布2023年中国石油和化工行业经济运行情况。数据显示&#xff0c;2023年&#xff0c;我国石化行业实现营业收入15.95万亿元&#xff0c; 同比下降1.1%&#xff0c;利润总额8733.6亿元&#xff0c;行业经济运行总体呈现低…

vscode搭建C/C++环境

文章目录 一、安装vscode 二、下载安装g 三、安装VSCode插件 四、配置运行环境 一、安装vscode 直接官网免费下载&#xff1a;下载完成后进行安装&#xff0c;记得更换安装路径Visual Studio Code - Code Editing. RedefinedVisual Studio Code is a code editor redefine…

大数据------额外插件及技术------Git(完整知识点汇总)

Git 定义 它是分布式版本控制工具&#xff0c;主要用于管理开发过程中的源代码文件&#xff08;如&#xff1a;Java类、xml文件、html页面等&#xff09;&#xff0c;在软件开发过程中被广泛应用 作用 代码回溯&#xff1a;快速回到某一代码历史版本版本切换&#xff1a;同一个…