java_web 日志配置

发布于:2025-09-01 ⋅ 阅读:(21) ⋅ 点赞:(0)

对于日志配置,我现在这个项目太老,使用的不是cicd自动化部署,还是传统的jar包启动,对于jar包启动,如果使用脚本来创建日志文件的话,日志文件比较固定,没办法每天都进行新日志的创建,不能进行日志细化,所以跟推荐在应用层面进行日志配置的创建。
比如我的脚本,如下

#!/bin/sh
# ==========================================
# RuoYi 启动脚本 (ry.sh)
# 支持: start | stop | restart | status
# 日志文件名: ruoyi-admin-2025-04-05.log(按天命名)
# ==========================================

AppName=ruoyi-admin.jar

# JVM 参数配置
JVM_OPTS="-Dname=$AppName -Duser.timezone=Asia/Shanghai -Xms512m -Xmx1024m -XX:MetaspaceSize=128m -XX:MaxMetaspaceSize=512m -XX:+HeapDumpOnOutOfMemoryError -XX:+PrintGCDateStamps -XX:+PrintGCDetails -XX:NewRatio=1 -XX:SurvivorRatio=30 -XX:+UseParallelGC -XX:+UseParallelOldGC"

# Java 命令路径
JAVA_CMD="/app/miniRun/jdk1.8.0_144/bin/java"
# 如使用系统 Java,可改为:JAVA_CMD="java"

# 应用路径
APP_HOME=$(cd $(dirname $0); pwd)
LOG_DIR=$APP_HOME/logs

# 👇 提取基础名(ruoyi-admin),加上日期
LOG_NAME=$(basename $AppName .jar)  # → ruoyi-admin
LOG_DATE=$(date +%Y-%m-%d)         # → 2025-04-05
LOG_PATH=$LOG_DIR/${LOG_NAME}-${LOG_DATE}.log  # → logs/ruoyi-admin-2025-04-05.log

# 颜色定义
RED='\033[0;31m'
GREEN='\033[0;32m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color

# 创建日志目录
mkdir -p "$LOG_DIR"


# 参数检查
if [ -z "$1" ]; then
    echo -e "${RED}❌ 未输入操作名${NC}  ${BLUE}{start|stop|restart|status}${NC}"
    echo "用法: $0 {start|stop|restart|status}"
    exit 1
fi

if [ -z "$AppName" ]; then
    echo -e "${RED}❌ 未设置应用名${NC}"
    exit 1
fi

# 检查 Java 是否可用
if [ ! -x "$JAVA_CMD" ] && ! command -v $JAVA_CMD >/dev/null 2>&1; then
    echo -e "${RED}❌ 找不到 Java 命令: $JAVA_CMD${NC}"
    exit 1
fi


# ================== 函数定义 ==================

function start() {
    PID=$(ps -ef | grep java | grep "$AppName" | grep -v grep | awk '{print $2}')
    if [ -n "$PID" ]; then
        echo -e "${GREEN}$AppName 已在运行 (PID: $PID)${NC}"
    else
        echo "🚀 正在启动 $AppName ..."
        # 每次启动都写入当天的日志文件
        nohup $JAVA_CMD $JVM_OPTS -jar $AppName --spring.profiles.active=pro >> $LOG_PATH 2>&1 &
        
        sleep 3
        PID=$(ps -ef | grep java | grep "$AppName" | grep -v grep | awk '{print $2}')
        if [ -n "$PID" ]; then
            echo -e "${GREEN}✅ 启动成功 (PID: $PID),日志路径: $LOG_PATH${NC}"
        else
            echo -e "${RED}❌ 启动失败,请检查日志: $LOG_PATH${NC}"
        fi
    fi
}

function stop() {
    echo "🛑 正在停止 $AppName ..."
    query() {
        PID=$(ps -ef | grep java | grep "$AppName" | grep -v grep | awk '{print $2}')
    }
    query
    if [ -n "$PID" ]; then
        kill -TERM $PID
        if [ $? -ne 0 ]; then
            echo -e "${RED}❌ 无法终止进程 (PID: $PID)${NC}"
            return 1
        fi
        echo "⏳ $AppName (PID: $PID) 正在退出..."
        while [ -n "$PID" ]; do
            sleep 1
            query
        done
        echo -e "${GREEN}$AppName 已停止${NC}"
    else
        echo -e "${BLUE}ℹ️ $AppName 已经停止${NC}"
    fi
}

function restart() {
    echo "🔄 正在重启 $AppName ..."
    stop
    sleep 2
    start
}

function status() {
    PID=$(ps -ef | grep java | grep "$AppName" | grep -v grep | awk '{print $2}')
    if [ -n "$PID" ]; then
        echo -e "${GREEN}$AppName 正在运行 (PID: $PID),日志: $LOG_PATH${NC}"
    else
        echo -e "${RED}$AppName 未运行${NC}"
    fi
}


# ================ 主命令分发 ================

case $1 in
    start)
        start
        ;;
    stop)
        stop
        ;;
    restart)
        restart
        ;;
    status)
        status
        ;;
    *)
        echo -e "${RED}❌ 未知命令: $1${NC}"
        echo "用法: $0 {start|stop|restart|status}"
        exit 1
        ;;
esac

这种虽然可以根据当天时间进行创建日志文件,但是只会在启动的时候进行创建,之后的所有内容都写在这个日志文件里面了,因为log_path是在第一次启动的时候就固定好的路径,之后并不会在更改。

那么如何在应用层面进行日志的创建呢?推荐使用logbak进行日志操作。

logbak

Logback是一个Java日志框架,是log4j项目的继承者,也是log4j创始人设计的另一个开源日志组件,性能比log4j要好。它旨在解决log4j存在的一些问题,并提供了更高效和更灵活的日志框架。

三个模块

logback-core:它是 Logback 的核心模块,提供了基本的日志功能。它支持多种输出格式和输出目标,包括控制台输出、文件输出和 Socket 输出。logback-core 可以与其他日志框架集成,例如 log4j 和 JDK Logging。

logback-classic:它是 Logback 的经典模块,是 log4j 的改进版。它提供了更强大的日志功能,并且向下兼容 log4j。它还支持 SLF4J,可以在不修改代码的情况下将应用程序从一个日志框架切换到另一个日志框架。

logback-access:它是 Logback 的访问模块,提供了基于 HTTP 请求的访问日志记录功能。使用 logback-access,可以记录每个请求的详细信息,包括请求方法、URL、响应状态码等。

使用

普通的使用是需要

@SpringBootApplication
public class SpringBoot303LoggingApplication {

//引入这段,声明一个Logger对象才可以使用
    private static Logger log = LoggerFactory.getLogger(SpringBoot303LoggingApplication.class);

    public static void main(String[] args) {
        SpringApplication.run(SpringBoot303LoggingApplication.class, args);

        log.info("启动完成");
    }
}

如果你使用了lombok,你可以直接通过注解**@slf4j**,使用后,可以直接使用log进行。

@RestController
@RequestMapping("/reimburse")
@Slf4j //使用这个注解
public class ReimburseController extends BaseController {
    /**
     * 获取发票识别结果
     */
    @PostMapping("/invoice-ocr-result")
    public AjaxResult getOcrInvoiceResult(MultipartFile file) throws Exception {
        log.info();
        }
  }

slf4j

而这些都是通过门户,Slf4J,即简单日志门面(Simple Logging Facade for Java),不是具体的日志解决方案,它只服务于各种各样的日志系统。按照官方的说法,Slf4J是一个用于日志系统的简单Facade,允许最终用户在部署其应用时使用其所希望的日志系统。

从某种程度上,Slf4J有点类似JDBC,不过比JDBC更简单,在JDBC中,你需要指定驱动程序,而在使用Slf4J的时候,不需要在代码中或配置文件中指定你打算使用那个具体的日志系统。如同使用JDBC基本不用考虑具体数据库一样,Slf4J提供了统一的记录日志的接口,只要按照其提供的方法记录即可,最终日志的格式、记录级别、输出方式等通过具体日志系统的配置来实现,因此可以在应用中灵活切换日志系统。

springboot3的默认配置

而我们这里要使用的就是slf4j加上logbak的日志配置,在springboot3中默认就是这一套配置,可以直接引入spring-boot-logging-starter使用。

            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-logging</artifactId>
                <version>3.5.3</version>
            </dependency>

自定义配置

logback.xml,放在resources下面,spring会自动识别。

<?xml version="1.0" encoding="UTF-8"?>
<!--
    scan:当此属性设置为true时,配置文件如果发生改变,将会被重新加载,默认值为true。
    scanPeriod:设置监测配置文件是否有修改的时间间隔,如果没有给出时间单位,默认单位是毫秒;当scan为true时,此属性生效。默认的时间间隔为1分钟。
    debug:当此属性设置为true时,将打印出logback内部日志信息,实时查看logback运行状态。默认值为false。
-->
<configuration scan="false" scanPeriod="60 seconds" debug="false">
    <!-- 定义日志的根目录,可以是相对路径或者绝对路径,路径不存在时,服务启动后会自动创建 -->
    <property name="LOG_HOME" value="logs"/>
    <!-- 定义日志文件名称 -->
    <property name="appName" value="systemLog"></property>

    <!-- 控制台日志输出:ch.qos.logback.core.ConsoleAppender-->
    <appender name="CONSOLE-LOG" class="ch.qos.logback.core.ConsoleAppender">
        <!--
        日志输出格式:
			%d表示日期时间,
			%thread表示线程名,
			%-5level:级别从左显示5个字符宽度
			%logger{50} 表示logger名字最长50个字符,否则按照句点分割。
			%line:表示行号
			%msg:日志消息
			%n是换行符
        -->
        <layout class="ch.qos.logback.classic.PatternLayout">
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} ==> [%thread] ==> %-5level %logger{50} : %line - %msg%n</pattern>
        </layout>
    </appender>

    <!--文件滚动输出:ERROR 级别的错误日志单独记录到指定文件中,方便后期排查 -->
    <appender name="FILE-ERROR-LOG" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <!-- 指定日志文件的路径,不存在时自动创建,可以是相对路径或绝对路径(如E:/temp/logs),${appName} 取的上面 property 定义的属性值-->
        <!--滚动策略外围不指定文件路径时,则直接使用滚动策略下的 fileNamePattern 的规则命名 -->
        <!--<file>${LOG_HOME}/${appName}.log</file>-->

        <!--阈值日志过滤器-ThresholdFilter:低于指定级别的事件将不被记录,等于或高于指定级别的事件将触发-->
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <level>ERROR</level>
        </filter>

        <!--滚动策略:当发生滚动时,决定 RollingFileAppender 的行为,涉及文件移动和重命名
        TimeBasedRollingPolicy: 最常用的滚动策略,它根据时间来制定滚动策略,既负责滚动也负责出发滚动。-->
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <!--滚动时产生的文件的存放位置及文件名称 %d{yyyy-MM-dd}:按天进行日志滚动
            %i:当文件大小超过maxFileSize时,按照i进行文件滚动-->
            <fileNamePattern>${LOG_HOME}/${appName}/error/%d{yyyy-MM-dd}-%i.log</fileNamePattern>
            <!--可选节点,控制保留的归档文件的最大数量,超出数量就删除旧文件。假设设置每天滚动,
            且maxHistory是365,则只保存最近365天的文件,删除之前的旧文件。注意,删除旧文件是,
            那些为了归档而创建的目录也会被删除。-->
            <MaxHistory>365</MaxHistory>
            <!--当日志文件超过maxFileSize指定的大小时,根据上面提到的%i进行日志文件滚动
            注意此处配置SizeBasedTriggeringPolicy是无法实现按文件大小进行滚动的,必须配置timeBasedFileNamingAndTriggeringPolicy
            -->
            <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                <maxFileSize>100MB</maxFileSize>
            </timeBasedFileNamingAndTriggeringPolicy>
        </rollingPolicy>
        <!-- 日志输出格式: -->
        <layout class="ch.qos.logback.classic.PatternLayout">
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [ %thread ] - [ %-5level ] [ %logger{50} : %line ] - %msg%n</pattern>
        </layout>
    </appender>

    <!--文件滚动输出:错误日志以外的日志统一记录,当然每个日志级别单独记录也是可以的,但是没太必要 -->
    <appender name="FILE-INFO-LOG" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <!-- 指定日志文件的路径,不存在时自动创建,可以是相对路径或绝对路径,${appName} 取的上面 property 定义的属性值-->
        <!--滚动策略外围不指定文件路径时,则直接使用滚动策略下的 fileNamePattern 的规则命名 -->
        <!--<file>${LOG_HOME}/${appName}.log</file>-->

        <!--级别日志过滤器-LevelFilter:按相等级别筛选事件的类,onMatch 表示是 level 指定的级别日志时,onMismatch 表示不是 level 指定的级别日志时-->
        <!--DENY 表示拒绝,ACCEPT 表示接受,NEUTRAL 表示中立-->
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>ERROR</level>
            <onMatch>DENY</onMatch>
            <onMismatch>ACCEPT</onMismatch>
        </filter>

        <!--滚动策略:当发生滚动时,决定 RollingFileAppender 的行为,涉及文件移动和重命名
        TimeBasedRollingPolicy: 最常用的滚动策略,它根据时间来制定滚动策略,既负责滚动也负责出发滚动。-->
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <!--滚动时产生的文件的存放位置及文件名称 %d{yyyy-MM-dd}:按天进行日志滚动%i:当文件大小超过maxFileSize时,按照i进行文件滚动-->
            <fileNamePattern>${LOG_HOME}/${appName}/info/%d{yyyy-MM-dd}-%i.log</fileNamePattern>
            <!--可选节点,控制保留的归档文件的最大数量,超出数量就删除旧文件。假设设置每天滚动,
            且maxHistory是365,则只保存最近365天的文件,删除之前的旧文件。注意,删除旧文件时那些为了归档而创建的目录也会被删除。-->
            <MaxHistory>365</MaxHistory>
            <!--当日志文件超过maxFileSize指定的大小时,根据上面提到的%i进行日志文件滚动
            注意此处配置SizeBasedTriggeringPolicy是无法实现按文件大小进行滚动的,必须配置timeBasedFileNamingAndTriggeringPolicy-->
            <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                <maxFileSize>100MB</maxFileSize>
            </timeBasedFileNamingAndTriggeringPolicy>
        </rollingPolicy>
        <!-- 日志输出格式: -->
        <layout class="ch.qos.logback.classic.PatternLayout">
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [ %thread ] - [ %-5level ] [ %logger{50} : %line ] - %msg%n</pattern>
        </layout>
    </appender>

    <!-- 异步输出文件,appender-ref 指向上面的同步输出即可 -->
    <appender name="ASYNC-INFO" class="ch.qos.logback.classic.AsyncAppender">
        <!-- 不丢失日志.默认的,如果队列的80%已满,则会丢弃TRACT、DEBUG、INFO级别的日志 -->
        <discardingThreshold>0</discardingThreshold>
        <!-- 更改默认的队列的深度,该值会影响性能.默认值为256 -->
        <queueSize>256</queueSize>
        <!-- 添加附加的appender,最多只能添加一个 -->
        <appender-ref ref="FILE-INFO-LOG"/>
    </appender>

    <!--异步输出文件,appender-ref 指向上面的同步输出即可-->
    <appender name="ASYNC-ERROR" class="ch.qos.logback.classic.AsyncAppender">
        <!-- 不丢失日志.默认的,如果队列的80%已满,则会丢弃TRACT、DEBUG、INFO级别的日志 -->
        <discardingThreshold>0</discardingThreshold>
        <!-- 更改默认的队列的深度,该值会影响性能.默认值为256 -->
        <queueSize>256</queueSize>
        <!-- 添加附加的appender,最多只能添加一个 -->
        <appender-ref ref="FILE-ERROR-LOG"/>
    </appender>

    <!--
        logger主要用于存放日志对象,也可以定义日志类型、级别
        name:表示匹配的logger类型前缀,也就是包的前半部分
        level:要记录的日志级别,包括 ALL < TRACE < DEBUG < INFO < WARN < ERROR < FATAL < OFF
        additivity:作用在于children-logger是否使用 rootLogger配置的appender进行输出,
        false:表示只用当前logger的appender-ref,true:
        表示当前logger的appender-ref和rootLogger的appender-ref都有效
    -->
    <!-- Spring framework logger -->
    <logger name="org.springframework" level="debug" additivity="false"></logger>
    <!-- app logger -->
    <!--<logger name="com.wmx" level="DEBUG"/>-->

    <!--1、root与logger是父子关系,没有特别定义则默认为root。
        2、任何一个类只会和一个logger对应,要么是定义的logger,要么是root,判断的关键在于找到这个logger,然后判断这个logger的appender和level。
        3、appender-ref 用于引用上面定义好的 appender 日志追加器,只有引用了,上面的 appender 才能生效. -->
    <root level="DEBUG">
        <appender-ref ref="CONSOLE-LOG"/>
        <!--需要异步写入文件中时,开启异步追究器-->
        <appender-ref ref="ASYNC-INFO"/>
        <appender-ref ref="ASYNC-ERROR"/>
        <!--需要同步写入文件中时,开启同步追究器-->
        <!--<appender-ref ref="FILE-INFO-LOG"/>-->
        <!--<appender-ref ref="FILE-ERROR-LOG"/>-->
    </root>
</configuration>

网站公告

今日签到

点亮在社区的每一天
去签到