I. Main points of this paper

Develop a system, including at least the development environment, test environment, formal environment, so that the system can run in different environments run different configurations, such as database, Redis, etc., with text code, It will show you how to integrate springBoot + Maven + Logback + Properties multi-environment configuration. A complete catalog of articles in the series

  • Springboot and Maven Multi-environment Profiles

  • Logback Multi-environment configuration

  • Logback Scrolls and compresses logs by day

Second, development environment

  • JDK 1.8
  • Maven 3.6.2
  • Lombok 1.18.18
  • Springboot 2.4.3
  • idea 2020

Modify the Maven configuration file pom.xml

1. Added profiles tabs dev, test, prod for development, test, and official environments.

<profiles>
    <profile>
        <id>dev</id>
        <activation>
            <activeByDefault>true</activeByDefault>
        </activation>
        <properties>
            <spring.profiles.active>dev</spring.profiles.active>
        </properties>
    </profile>
    <profile>
        <id>test</id>
        <properties>
            <spring.profiles.active>test</spring.profiles.active>
        </properties>
    </profile>
    <profile>
        <id>prod</id>
        <properties>
            <spring.profiles.active>prod</spring.profiles.active>
        </properties>
    </profile>
</profiles>
Copy the code

2. Enable the development environment by default.

<activation>
    <activeByDefault>true</activeByDefault>
</activation>
Copy the code

Modify the application. Properties project

1. Modify application.properties to receive profile parameters from Maven or command line.

spring.profiles.active=@spring.profiles.active@
Copy the code

Properties; test application-test.properties; application-prod.properties;

Add Logback configuration file logback-spring. XML

Why not logback.xml instead of logback-spring.xml? The main reason is that we need to use the configuration in application-xxx.properties in the logback configuration file, for example, we can add logging.file.path=./logs in application-dev.properties


      
<! -- Log levels are TRACE < DEBUG < INFO < WARN < ERROR < FATAL. If set to WARN, messages lower than WARN will not be printed -->
<! -- scan: When this property is set to true, the configuration file will be reloaded if it changes. The default value is true -->
<! -- scanPeriod: sets the interval for checking whether the configuration file has been modified. If no time unit is given, the default unit is milliseconds. This attribute takes effect when scan is true. The default interval is 1 minute. -->
<! -- debug:When the value is set to true, internal logback logs are displayed to view the running status of logback in real time. The default value is false. -->
<configuration  scan="true" scanPeriod="10 seconds">

    <! --<include resource="org/springframework/boot/logging/logback/base.xml" />-->

    <contextName>logback</contextName>
    <! The value of name is the name of the variable, and the value of value is the value defined by the variable. The defined values are inserted into the Logger context. After you define variables, you can make "${}" to use them. -->
    <springProperty scope="context" name="log.path" source="logging.file.path"/>

    <! -- Output to console -->
    <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <Pattern>[%d{yyyy-MM-dd HH:mm:ss.SSS}] [%thread] [%level] [%logger{50}:%L] - %msg%n</Pattern>
            <! -- Set character set -->
            <charset>UTF-8</charset>
        </encoder>
    </appender>

    <! -- Output to file -->

    <! -- DEBUG log -->
    <appender name="DEBUG_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <! -- The path and name of the log file being recorded -->
        <file>${log.path}/log_debug.log</file>
        <! Log file output format -->
        <encoder>
            <pattern>[%d{yyyy-MM-dd HH:mm:ss.SSS}] [%thread] [%level] [%logger{50}:%L] - %msg%n</pattern>
            <charset>UTF-8</charset> <! -- Set character set -->
        </encoder>
        <! -- Logger scroll policy, by date, by size -->
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <! -- Log Archive -->
            <fileNamePattern>${log.path}/debug/log-debug-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
            <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                <maxFileSize>100MB</maxFileSize>
            </timeBasedFileNamingAndTriggeringPolicy>
            <! -- Log file retention days -->
            <maxHistory>7</maxHistory>
            <totalSizeCap>1GB</totalSizeCap>
            <cleanHistoryOnStart>true</cleanHistoryOnStart>
        </rollingPolicy>
        <! -- This log file only records debug level -->
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>debug</level>
            <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>
    </appender>

    <! -- Log level = INFO -->
    <appender name="INFO_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <! -- The path and name of the log file being recorded -->
        <file>${log.path}/log_info.log</file>
        <! Log file output format -->
        <encoder>
            <pattern>[%d{yyyy-MM-dd HH:mm:ss.SSS}] [%thread] [%level] [%logger{50}:%L] - %msg%n</pattern>
            <charset>UTF-8</charset>
        </encoder>
        <! -- Logger scroll policy, by date, by size -->
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <! -- Daily log archive path and format -->
            <fileNamePattern>${log.path}/info/log-info-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
            <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                <maxFileSize>200MB</maxFileSize>
            </timeBasedFileNamingAndTriggeringPolicy>
            <! -- Log file retention days -->
            <maxHistory>7</maxHistory>
            <totalSizeCap>2GB</totalSizeCap>
            <cleanHistoryOnStart>true</cleanHistoryOnStart>
        </rollingPolicy>
        <! -- This log file only records info level -->
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>info</level>
            <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>
    </appender>

    <! Log level = WARN -->
    <appender name="WARN_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <! -- The path and name of the log file being recorded -->
        <file>${log.path}/log_warn.log</file>
        <! Log file output format -->
        <encoder>
            <pattern>[%d{yyyy-MM-dd HH:mm:ss.SSS}] [%thread] [%level] [%logger{50}:%L] - %msg%n</pattern>
            <charset>UTF-8</charset> <! -- Set character set -->
        </encoder>
        <! -- Logger scroll policy, by date, by size -->
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <fileNamePattern>${log.path}/warn/log-warn-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
            <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                <maxFileSize>100MB</maxFileSize>
            </timeBasedFileNamingAndTriggeringPolicy>
            <! -- Log file retention days -->
            <maxHistory>7</maxHistory>
            <totalSizeCap>200MB</totalSizeCap>
            <cleanHistoryOnStart>true</cleanHistoryOnStart>
        </rollingPolicy>
        <! This log file records only logs of warn level -->
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>warn</level>
            <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>
    </appender>


    <! -- Log level = ERROR -->
    <appender name="ERROR_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <! -- The path and name of the log file being recorded -->
        <file>${log.path}/log_error.log</file>
        <! Log file output format -->
        <encoder>
            <pattern>[%d{yyyy-MM-dd HH:mm:ss.SSS}] [%thread] [%level] [%logger{50}:%L] - %msg%n</pattern>
            <charset>UTF-8</charset> <! -- Set character set -->
        </encoder>
        <! -- Logger scroll policy, by date, by size -->
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <fileNamePattern>${log.path}/error/log-error-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
            <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                <maxFileSize>200MB</maxFileSize>
            </timeBasedFileNamingAndTriggeringPolicy>
            <! -- Log file retention days -->
            <maxHistory>15</maxHistory>
            <totalSizeCap>1GB</totalSizeCap>
            <cleanHistoryOnStart>true</cleanHistoryOnStart>
        </rollingPolicy>
        <! -- This log file only records ERROR levels -->
       <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>ERROR</level>
            <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>
    </appender>

    <! -- Asynchronous output -->
    <appender name="ASYNC_CONSOLE" class="ch.qos.logback.classic.AsyncAppender">
        <! -- Do not lose logs. By default, TRACT, DEBUG, and INFO logs are discarded if 80% of the queue is full.
        <discardingThreshold>0</discardingThreshold>
        <! Change the default queue depth, which affects performance. The default is 256 -->
        <queueSize>256</queueSize>
        <! Add additional appenders, one at most -->
        <appender-ref ref="CONSOLE"/>
    </appender>

    <appender name="ASYNC_DEBUG" class="ch.qos.logback.classic.AsyncAppender">
        <appender-ref ref="DEBUG_FILE"/>
        <includeCallerData>true</includeCallerData>
    </appender>
    <appender name="ASYNC_INFO" class="ch.qos.logback.classic.AsyncAppender">
        <appender-ref ref="INFO_FILE"/>
        <includeCallerData>true</includeCallerData>
    </appender>
    <appender name="ASYNC_WARN" class="ch.qos.logback.classic.AsyncAppender">
        <appender-ref ref="WARN_FILE"/>
        <includeCallerData>true</includeCallerData>
    </appender>
    <appender name="ASYNC_ERROR" class="ch.qos.logback.classic.AsyncAppender">
        <appender-ref ref="ERROR_FILE"/>
        <includeCallerData>true</includeCallerData>
    </appender>

    <springProfile name="dev">

        <root level="DEBUG">
            <appender-ref ref="ASYNC_CONSOLE" />
            <appender-ref ref="ASYNC_DEBUG"/>
            <appender-ref ref="ASYNC_INFO"/>
            <appender-ref ref="ASYNC_WARN"/>
            <appender-ref ref="ASYNC_ERROR"/>
        </root>

    </springProfile>

    <springProfile name="test">

        <root level="DEBUG">
            <appender-ref ref="ASYNC_DEBUG"/>
            <appender-ref ref="ASYNC_INFO"/>
            <appender-ref ref="ASYNC_WARN"/>
            <appender-ref ref="ASYNC_ERROR"/>
        </root>

    </springProfile>

    <springProfile name="prod">

        <root level="INFO">
            <appender-ref ref="ASYNC_DEBUG"/>
            <appender-ref ref="ASYNC_INFO"/>
            <appender-ref ref="ASYNC_WARN"/>
            <appender-ref ref="ASYNC_ERROR"/>
        </root>

    </springProfile>

</configuration>
Copy the code

If you need to compress history logs, just change the.log suffix to.zip, for example.

    <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
        <fileNamePattern>${log.path}/warn/log-warn-%d{yyyy-MM-dd}.%i.zip</fileNamePattern>
        <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
            <maxFileSize>100MB</maxFileSize>
        </timeBasedFileNamingAndTriggeringPolicy>
        <! -- Log file retention days -->
        <maxHistory>7</maxHistory>
        <totalSizeCap>200MB</totalSizeCap>
        <cleanHistoryOnStart>true</cleanHistoryOnStart>
    </rollingPolicy>
Copy the code

Six, run it

1. The complete project structure is as follows.

2. Add the following code to application-dev.properties.

logging.file.path=./logs
Copy the code

3. Add the following code to application-test.properties.

logging.file.path=./logs-test
Copy the code

4. Change the Active profiles to dev or test to view the project log structure.

You can see that the log output directories in the development environment and test environment are different.

Seven, summary

A few simple steps to enable the project to support multiple environment configurations, is not very simple, complete code address: here. Docker build a development environment to install Mysql

Add me to exchange learning!