基于Eureka搭建Springcloud微服务-20.综合案例

lingwh原创2020年7月29日大约 17 分钟约 5235 字

20.综合案例

20.1.章节内容概述

本章节涉及主要内容有:
 20.1.章节内容概述
 20.2.章节内容大纲
 20.3.综合案例简介
 20.4.在父工程pom.xml添加多环境配置
 20.5.搭建单节点版EUREKA注册中心
 20.6.搭建服务提供者第一个节点
 20.7.搭建服务提供者第二个节点
 20.8.搭建服务消费者
 20.9.搭建SpringBootAdminServer
 20.10.测试适用于生产环境的微服务
具体每个小节中包含的内容可使通过下面的章节内容大纲进行查看。

20.2.章节内容大纲

20.3.综合案例简介

综合案例会将前面所有章节提到的技术整合在一起,具体整合的技术有
a.多环境相关配置
  多环境运行
  多环境打包
  多环境推送到Docker
b.微服务监控技术
  SpringBootAdmin
c.更完善的日志系统
  集成logback日志(输出到控制台+输出到文件)
  使用Logstash推送日志到ELK中
  在日志中输出调用链路信息(集成Zipkin+Sleuth,实现在日志中输出TraceId和SpanId和Span-Export)
d.持续集成技术:
  持续集成到Docker
  持续集成到Kubernetes
e.更好的使用OpenFeign
  实现OpenFeign动态服务名称和动态URL调用

20.4.在父工程pom.xml添加多环境配置

如果父工程pom.xml已经添加了多环境相关的配置,则这一步骤可以省略,如没有添加,请在pom.xml中添加如下内容
<!--定义多种开发环境:开始-->
<profiles>
    <!--开发环境-->
    <profile>
        <!--不同环境的唯一id-->
        <id>dev</id>
        <properties>
            <!--profile.active对应application.yml中的@profile.active@-->
            <profile.active>dev</profile.active>
            <!--dev环境docker私服连接信息(使用docker官方提供的私服):开始-->
            <docker.registry.uri>192.168.0.4:5000</docker.registry.uri>
            <docker.registry.username>docker</docker.registry.username>
            <docker.registry.password>123456</docker.registry.password>
            <!--dev环境docker私服连接信息(使用docker官方提供的私服):结束-->
            <!--dev环境docker部署地址:端口-->
            <docker.host>tcp://192.168.0.4:2375</docker.host>
        </properties>
    </profile>

    <!--测试环境-->
    <profile>
        <id>test</id>
        <properties>
            <profile.active>test</profile.active>
            <!--test环境docker私服连接信息(vmware提供的私服的harbor私服):开始-->
            <docker.registry.uri>192.168.0.4:5001</docker.registry.uri>
            <docker.registry.username>admin</docker.registry.username>
            <docker.registry.password>123456</docker.registry.password>
            <!--dev环境docker私服连接信息(vmware提供的私服的harbor私服):结束-->
            <!--dev环境docker部署地址:端口-->
            <docker.host>tcp://192.168.0.4:2375</docker.host>
        </properties>
    </profile>

    <!--生产环境-->
    <profile>
        <id>prod</id>
        <properties>
            <profile.active>prod</profile.active>
            <!--prod环境docker私服连接信息(使用docker官方提供的私服):开始-->
            <docker.registry.uri>192.168.0.4:5000</docker.registry.uri>
            <docker.registry.username>docker</docker.registry.username>
            <docker.registry.password>123456</docker.registry.password>
            <!--prod环境docker私服连接信息(使用docker官方提供的私服):结束-->
            <!--prod环境docker部署地址:端口-->
            <docker.host>tcp://192.168.0.4:2375</docker.host>
        </properties>
        <activation>
            <!--默认激活环境-->
            <activeByDefault>true</activeByDefault>
        </activation>
    </profile>

    <!--rancher测试专用环境-->
    <profile>
        <id>rancher</id>
        <properties>
            <profile.active>rancher</profile.active>
            <!--rancher环境docker私服连接信息(vmware提供的私服的harbor私服):开始-->
            <docker.registry.uri>192.168.0.4:5001</docker.registry.uri>
            <docker.registry.username>admin</docker.registry.username>
            <docker.registry.password>123456</docker.registry.password>
            <!--rancher环境docker私服连接信息(vmware提供的私服的harbor私服):结束-->
            <!--rancher环境docker部署地址:端口-->
            <docker.host>tcp://192.168.0.4:2375</docker.host>
        </properties>
    </profile>
</profiles>
<!--定义多种开发环境:结束-->

20.5.搭建单节点版EUREKA注册中心

20.5.1.章节内容简介

为综合案例搭建单节点版的Eureka注册中心

20.5.2.模块简介

适用于生产环境的单节点版Eureka注册中心,启动端口: 7005

20.5.3.模块目录结构

springcloud-basic-sample-register-center-single-node7005
|-- docker
|   •-- Dockerfile
|-- src
|   •-- main
|       |-- java
|       |   •-- org
|       |       •-- openatom
|       |           •-- springcloud
|       |               |-- config
|       |               |   •-- VirtualIpConfig.java
|       |               •-- BasicSampleRegisterCcenterSingleNode7005.java
|       •-- resources
|           |-- dev
|           |   |-- application-dev.yml
|           |   |-- application.yml
|           |   •-- logback-custom.xml
|           |-- prod
|           |   |-- application-prod.yml
|           |   |-- application.yml
|           |   •-- logback-custom.xml
|           |-- rancher
|           |   |-- application-rancher.yml
|           |   |-- application.yml
|           |   •-- logback-custom.xml
|           •-- test
|               |-- application-test.yml
|               |-- application.yml
|               •-- logback-custom.xml
•-- pom.xml

20.5.4.创建模块

在父工程(springcloud-eureka)中创建一个名为springcloud-basic-sample-register-center-single-node7005的maven模块,注意:当前模块创建成功后,在父工程pom.xml中<modules></modules>中会自动生成有关当前模块的信息

20.5.5.编写模块pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>springcloud-eureka</artifactId>
        <groupId>org.openatom</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>springcloud-basic-sample-register-center-single-node7005</artifactId>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
        <!--设置当前服务端口-->
        <docker.container.port>7005</docker.container.port>
        <!--docker容器端口映射-->
        <docker.port.mapping>${docker.container.port}:${docker.container.port}</docker.port.mapping>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
        </dependency>
        <!--引入公共的工程-->
        <dependency>
            <groupId>org.openatom</groupId>
            <artifactId>springcloud-api-commons</artifactId>
        </dependency>
        <dependency>
            <groupId>net.logstash.logback</groupId>
            <artifactId>logstash-logback-encoder</artifactId>
        </dependency>
        <dependency>
            <groupId>de.codecentric</groupId>
            <artifactId>spring-boot-admin-starter-client</artifactId>
        </dependency>
    </dependencies>

    <!--热部署需要加这个-->
    <build>
        <finalName>${project.artifactId}</finalName>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <executions>
                    <execution>
                        <!--把当前插件repackage命令和maven的package绑定-->
                        <id>repackage-original</id>
                        <phase>package</phase>
                        <goals>
                            <goal>repackage</goal>
                        </goals>
                    </execution>
                </executions>
                <configuration>
                    <fork>true</fork>
                    <addResources>true</addResources>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-resources-plugin</artifactId>
                <configuration>
                    <encoding>UTF-8</encoding>
                    <delimiters>
                        <delimiter>@</delimiter>
                    </delimiters>
                    <useDefaultDelimiters>false</useDefaultDelimiters>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-antrun-plugin</artifactId>
                <executions>
                    <execution>
                        <id>del-jar</id>
                        <phase>clean</phase>
                        <configuration>
                            <tasks>
                                <!-- 这是将当前模块下的target下的jar包删除-->
                                <delete file="docker/${build.finalName}.jar"/>
                            </tasks>
                        </configuration>
                        <goals>
                            <goal>run</goal>
                        </goals>
                    </execution>
                    <execution>
                        <id>copy-jar</id>
                        <phase>install</phase>
                        <configuration>
                            <tasks>
                                <!-- 这是将当前模块下的target下的jar包copy到当前模块根目录下docker目录中-->
                                <copy todir="docker" file="target/${build.finalName}.jar"></copy>
                            </tasks>
                        </configuration>
                        <goals>
                            <goal>run</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
            <plugin>
                <groupId>io.fabric8</groupId>
                <artifactId>docker-maven-plugin</artifactId>
                <configuration>
                    <dockerHost>${docker.host}</dockerHost>
                    <removeMode>true</removeMode>
                    <!--
                        harbor镜像仓库认证配置
                        注意:不管是harbor中是公开项目还是私密项目,这个配置都要加,不加无法push成功
                    -->
                    <authConfig>
                        <username>${docker.registry.username}</username>
                        <password>${docker.registry.password}</password>
                    </authConfig>
                    <images>
                        <image>
                            <!--显示日志的时候-->
                            <!--<alias>spring-cloud-eureka</alias>-->
                            <!--如果只给docker本地镜像库中推送,格式为 命名空间/项目名称:tags名称,示例:项目artifactId/模块artifactId-->
                            <!--<name>${project.parent.artifactId}/${project.name}</name>-->
                            <!--
                                如果要同时给私服中推送,格式为 registry的ip:命名空间/项目名称:tags名称,示例:私服的ip:项目artifactId/模块artifactId
                                也可将registry单独写在下面
                            -->
                            <!--<name>镜像名称:${docker.registry}/${project.parent.artifactId}/${project.name}</name>-->
                            <name>${project.parent.artifactId}/${project.name}:latest</name>
                            <registry>${docker.registry.uri}</registry>
                            <!--定义镜像构建行为-->
                            <build>
                                <!-- 指定dockerfile文件的位置-->
                                <dockerFile>${project.basedir}/docker/Dockerfile</dockerFile>
                            </build>

                            <!-- 定义容器启动行为-->
                            <run>
                                <!--设置容器名,可采用通配符-->
                                <containerNamePattern>${project.parent.artifactId}_${project.build.finalName}</containerNamePattern>
                                <!--设置端口映射-->
                                <ports>
                                    <port>${docker.port.mapping}</port>
                                </ports>
                            </run>
                        </image>
                    </images>
                    <buildArgs>
                        <!--docker私服地址-->
                        <DOCKER_REGISTRY_URL>${docker.registry.uri}</DOCKER_REGISTRY_URL>
                    </buildArgs>
                </configuration>
                <executions>
                    <!--如果想在项目install时构建镜像添加-->
                    <execution>
                        <id>build-image</id>
                        <phase>install</phase>
                        <goals>
                            <goal>build</goal>
                        </goals>
                    </execution>
                    <!--如果想在项目install时构建镜像添加-->
                    <execution>
                        <id>tag-image</id>
                        <phase>install</phase>
                        <goals>
                            <goal>tag</goal>
                        </goals>
                    </execution>
                    <!--如果想在项目install时推送镜像到私服添加-->
                    <execution>
                        <id>push-image</id>
                        <phase>install</phase>
                        <goals>
                            <goal>push</goal>
                        </goals>
                    </execution>
                    <!--如果想在项目install时推送镜像到私服后删除并docker中本地build的镜像添加-->
                    <execution>
                        <id>remove-image</id>
                        <phase>install</phase>
                        <goals>
                            <goal>remove</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
        <!--打包多环境-->
        <resources>
            <resource>
                <directory>src/main/resources</directory>
                <excludes>
                    <exclude>**/*.yml</exclude>
                    <exclude>**/*.xml</exclude>
                </excludes>
            </resource>
            <resource>
                <directory>src/main/resources/${profile.active}</directory>
                <!--引入所需环境的配置文件-->
                <filtering>true</filtering>
                <includes>
                    <include>application.yml</include>
                    <!--根据maven选择环境导入配置文件-->
                    <include>application-${profile.active}.yml</include>
                    <include>*.xml</include>
                </includes>
            </resource>
        </resources>
    </build>
</project>

20.5.6.编写模块配置文件

dev环境配置文件
application.yml
#设置spring项目运行的环境
spring:
  profiles:
    active: '@profile.active@'


application-dev.yml
server:
  port: 7005 #访问端口
spring:
  application:
    name: SPRINGCLOUD-BASIC-SAMPLE-REGISTER-CENTER-SINGLE-NODE7005-DEV  #注意:服务名不要出现_
  devtools: #热部署开关
    restart:
      enabled: true
# 将Client作为服务注册到SpringBootAdmin Server端,通过Server来监听项目的运行情况
  boot:
    admin:
      client:
        #因为eureka的配置先加载所以可以使用${eureka.instance.ip-address}这个来动态获取ip,虽然这个键值对配置在下面
        url: http://localhost:${server.port}
eureka:
  instance:
    hostname: localhost
  client:
    register-with-eureka: true #不向注册中心注册自己
    fetch-registry: false #表示自己就是注册中心,我的职责就是维护实例,不需要去检索服务
    service-url:
      defaultZone: http://localhost:7005/eureka
  server:
    enable-self-preservation: true #是否开启自我保护,true:服务失效不直接剔除,false:服务失效直接剔除
    eviction-interval-timer-in-ms: 2000 #默认发送心跳的时间间隔,单位为ms

#配置文件修改说明-------------------------------------------------:开始
#注意:不同的部署环境需要修改的配置
#   1.${logback.path}  #修改日志存放位置,Linxu为/,Windows为\
#       修改原因: Linux和Windows目录结构不同
#配置文件修改说明-------------------------------------------------:结束

#自定义日志配置文件路径
logging:
  config: classpath:logback-custom.xml
  path: D:\repository\workspace\IDEA\PERSONAL\springcloud-eureka\log\ #所有日志存放在位置,加上\方便Linux环境下配置
  level:
    root: info #全局日志输出级别

logback:
  log-name: ${spring.application.name}
  append: false #是否启用append(追加到已经存在日志文件尾部),true:重启项目会追加新日志到之前日志,false:重启项目会清空之前的日志
  immediate-flush: true #是否启用immediateFlush(立即刷新),true:重启项目自动追加,false:重启项目会情况之前的日志
  deploy-machine-ip: localhost #当前微服务所在部署机器ip

#logstash相关配置:开始
logstash:
  host: 192.168.0.4:5044 # logstash地址
  index: '@project.parent.artifactId@' # es中index名称
#logstash相关配置:结束

#actuator监控:开始
#通过下面的配置启用所有的监控端点,默认情况下,这些端点是禁用的;
management:
  endpoints:
    web:
      exposure:
        include: '*'
    enabled-by-default: true
  endpoint:
    health:
      show-details: always # 访问/actuator/health时,显示详细信息,而不是仅仅显示"status": "UP"
    # 日志文件路径:特别注意,此处无法配置日志文件路径,因为rancher会生成虚拟ip,这个虚拟ip是无法在这里获取的,
    #           但是虚拟ip是路径的一部分,所以这个路径无法拼接出来,所以这里无法配置日志文件路径
    #logfile:
    #  external-file:
#actuator监控:结束

logback-custom.xml
<?xml version="1.0" encoding="UTF-8"?>

<!--
    scan: 当此属性设置为true时,配置文件如果发生改变,将会被重新加载,默认值为true。
    scanPeriod: 设置监测配置文件是否有修改的时间间隔,如果没有给出时间单位,默认单位是毫秒。当scan为true时,此属性生效。默认的时间间隔为1分钟。
    debug: 当此属性设置为true时,将打印出logback内部日志信息,实时查看logback运行状态。默认值为false。
-->
<!-- 输出logback内部日志信息,每隔30s判断一下配置文件有没有更新,若更新,则重新加载 -->
<configuration scan="true" scanPeriod="30 seconds" debug="false">
    <!--从java代码中获取虚拟ip的值-->
    <!--获取当前微服务部署虚拟IP,如rancher为当前微服务分配的ip-->
    <define name="VIRTUAL_IP" class="org.openatom.springcloud.config.VirtualIpConfig"/>

    <!--从Spring容器中获取配置(Spring配置文件加载顺序:bootstrap.yml->logback.xml->application.yml)-->
    <!--获取当前微服务部署机器ip-->
    <springProperty name="MACHINE_IP" scope="context" source="logback.deploy-machine-ip"/>
    <!--应用名称-->
    <springProperty name="LOG_NAME" scope="context" source="logback.log-name"/>
    <!--是否启用append-->
    <springProperty name="IS_APPEND" scope="context" source="logback.append"/>
    <!--是否启用立即刷新-->
    <springProperty name="IS_IMMEDIATEFLUSH" scope="context" source="logback.immediate-flush"/>
    <springProperty name="LOG_PATH" scope="context" source="logging.path"/>
    <!--logstash地址-->
    <springProperty name="LOGSTASH_HOST" scope="context" source="logstash.host"/>
    <!--索引名称-->
    <springProperty name="INDEX_NAME" scope="context" source="logstash.index"/>


    <!-- name:变量的名称,可以随意起名,但建议名字要简明直译;value:变量的值;在配置文件中,我们可以用 ${} 的方式来使用,将变量引入到其他节点中去。-->
    <!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度 %msg:日志消息,%n是换行符-->
    <!--控制台日志输出预选样式-->
    <property name="CONSOLE_LOG_PATTERN_1" value="%red(%d{yyyy-MM-dd HH:mm:ss.SSS}) %green([%thread]) [machineIp:${MACHINE_IP} virtualIp:${VIRTUAL_IP}] [TraceId:%X{X-B3-TraceId:-} SpanId:%X{X-B3-SpanId:-} %highlight(%-5level) %boldMagenta(%logger{10}): %cyan(%msg%n)"/>
    <property name="CONSOLE_LOG_PATTERN_2" value="%yellow(%date{yyyy-MM-dd HH:mm:ss}) [machineIp:${MACHINE_IP} virtualIp:${VIRTUAL_IP}] [TraceId:%X{X-B3-TraceId:-} SpanId:%X{X-B3-SpanId:-} %highlight([%-5level]) %green(%logger) %msg%n"/>
    <property name="CONSOLE_LOG_PATTERN_3" value="%date{yyyy-MM-dd HH:mm:ss} [machineIp:${MACHINE_IP} virtualIp:${VIRTUAL_IP}] [TraceId:%X{X-B3-TraceId:-} SpanId:%X{X-B3-SpanId:-} Span-Export:%X{X-Span-Export:-}]  %green(%-5level) %boldMagenta(${PID:-}) -- [%+20thread] %cyan(%logger{20}) %line       : %msg%n"/>
    <!--文件中日志输出预选样式-->
    <property name="FILE_LOG_PATTERN_1" value="%d{yyyyMMdd:HH:mm:ss.SSS} [machineIp:${MACHINE_IP} virtualIp:${VIRTUAL_IP}] [TraceId:%X{X-B3-TraceId:-} SpanId:%X{X-B3-SpanId:-} [%thread] %-5level  %msg%n"/>

    <!--控制台日志输出格式-->
    <property name="CONSOLE_LOG_PATTERN" value="${CONSOLE_LOG_PATTERN_3}"/>
    <!--文件中日志输出格式-->
    <property name="FILE_LOG_PATTERN" value="${FILE_LOG_PATTERN_1}"/>
    <!--日志名称-->
    <!--定义默认日志输出级别-->
    <property name="LOG_OUTPUT_LEVEL" value="${LOG_LEVEL}" />
    <!--定义默认日志输出编码-->
    <property name="ENCODING" value="UTF-8" />

    <!-- 控制台输出:开始 -->
    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
        <!-- 用来设置日志的输入格式,使用“%+转换符”的方式,如果要输出”%”则必须使用”\”进行转义。-->
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <!-- 格式化输出:https://logback.qos.ch/manual/layouts.html
                 %d 表示日期,
                 %thread 表示线程名,
                 %level 日志级别从左显示5个字符宽度,
                 %t 线程名
                 %file:%line 文件名+行号,
                 %m 日志消息,%n是换行符
                 %X{traceId}:自定义设置的参数,后面会说。
            -->
            <pattern>${CONSOLE_LOG_PATTERN}</pattern>
            <charset>${ENCODING}</charset>
        </encoder>
    </appender>
    <!-- 控制台输出:结束 -->

    <!--输出到文件:开始-->
    <!-- 将项目本次运行INFO日志同步输出到文件,会自动清空文件中上一次的日志 -->
    <appender name="APPENDER-FILEAPPENDER-INFO" class="ch.qos.logback.core.FileAppender">
        <!-- 过滤器,只记录 info 级别以上的日志 -->
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <level>INFO</level>
        </filter>
        <!-- 写入的日志文件名,可以使相对目录也可以是绝对目录,如果上级目录不存在则自动创建 -->
        <file>${LOG_PATH}/${MACHINE_IP}/${VIRTUAL_IP}/${LOG_NAME}-info.log</file>
        <!-- 如果为true表示日志被追加到文件结尾,如果是false表示清空文件 -->
        <append>${IS_APPEND}</append>
        <!--立即刷新,设置成false可以提高日志吞吐量-->
        <immediateFlush>${IS_IMMEDIATEFLUSH}</immediateFlush>
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <pattern>${FILE_LOG_PATTERN}</pattern>
            <charset>${ENCODING}</charset>
        </encoder>
    </appender>

    <!-- 将项目本次运行INFO日志异步输出到文件,会自动清空文件中上一次的日志 -->
    <appender name="ASYNC-APPENDER-FILEAPPENDER-INFO" class="ch.qos.logback.classic.AsyncAppender">
        <appender-ref ref="APPENDER-FILEAPPENDER-INFO" />
        <!-- 设置异步阻塞队列的大小,为了不丢失日志建议设置的大一些,单机压测时100000是没问题的,应该不用担心OOM -->
        <queueSize>10000</queueSize>
        <!-- 设置丢弃DEBUG、TRACE、INFO日志的阀值,不丢失 -->
        <discardingThreshold>0</discardingThreshold>
        <!-- 设置队列入队时非阻塞,当队列满时会直接丢弃日志,但是对性能提升极大 -->
        <neverBlock>${IS_IMMEDIATEFLUSH}</neverBlock>
    </appender>

    <!-- 将项目本次运行DEBUG日志同步输出到文件,会自动清空文件中上一次的日志 -->
    <appender name="APPENDER-FILEAPPENDER-DEBUG" class="ch.qos.logback.core.FileAppender">
        <!-- 过滤器,只记录 info 级别以上的日志 -->
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <level>DEBUG</level>
        </filter>
        <!-- 写入的日志文件名,可以使相对目录也可以是绝对目录,如果上级目录不存在则自动创建 -->
        <file>${LOG_PATH}/${MACHINE_IP}/${VIRTUAL_IP}/${LOG_NAME}-debug.log</file>
        <!-- 如果为true表示日志被追加到文件结尾,如果是false表示清空文件 -->
        <append>${IS_APPEND}</append>
        <!--立即刷新,设置成false可以提高日志吞吐量-->
        <immediateFlush>true</immediateFlush>
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <pattern>${FILE_LOG_PATTERN}</pattern>
            <charset>${ENCODING}</charset>
        </encoder>
    </appender>

    <!-- 将项目本次运行DEBUG日志异步输出到文件,会自动清空文件中上一次的日志 -->
    <appender name="ASYNC-APPENDER-FILEAPPENDER-DEBUG" class="ch.qos.logback.classic.AsyncAppender">
        <appender-ref ref="APPENDER-FILEAPPENDER-DEBUG" />
        <!-- 设置异步阻塞队列的大小,为了不丢失日志建议设置的大一些,单机压测时100000是没问题的,应该不用担心OOM -->
        <queueSize>10000</queueSize>
        <!-- 设置丢弃DEBUG、TRACE、INFO日志的阀值,不丢失 -->
        <discardingThreshold>0</discardingThreshold>
        <!-- 设置队列入队时非阻塞,当队列满时会直接丢弃日志,但是对性能提升极大 -->
        <neverBlock>true</neverBlock>
    </appender>

    <!-- 将项目本次运行ERROR日志同步输出到文件,会自动清空文件中上一次的日志 -->
    <appender name="APPENDER-FILEAPPENDER-ERROR" class="ch.qos.logback.core.FileAppender">
        <!-- 过滤器,只记录 info 级别以上的日志 -->
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <level>DEBUG</level>
        </filter>
        <!-- 写入的日志文件名,可以使相对目录也可以是绝对目录,如果上级目录不存在则自动创建 -->
        <file>${LOG_PATH}/${MACHINE_IP}/${VIRTUAL_IP}/${LOG_NAME}-error.log</file>
        <!-- 如果为true表示日志被追加到文件结尾,如果是false表示清空文件 -->
        <append>${IS_APPEND}</append>
        <!--立即刷新,设置成false可以提高日志吞吐量-->
        <immediateFlush>${IS_IMMEDIATEFLUSH}</immediateFlush>
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <pattern>${FILE_LOG_PATTERN}</pattern>
            <charset>${ENCODING}</charset>
        </encoder>
    </appender>

    <!-- 将项目本次运行ERROR日志异步输出到文件,会自动清空文件中上一次的日志 -->
    <appender name="ASYNC-APPENDER-FILEAPPENDER-ERROR" class="ch.qos.logback.classic.AsyncAppender">
        <appender-ref ref="APPENDER-FILEAPPENDER-ERROR" />
        <!-- 设置异步阻塞队列的大小,为了不丢失日志建议设置的大一些,单机压测时100000是没问题的,应该不用担心OOM -->
        <queueSize>10000</queueSize>
        <!-- 设置丢弃DEBUG、TRACE、INFO日志的阀值,不丢失 -->
        <discardingThreshold>0</discardingThreshold>
        <!-- 设置队列入队时非阻塞,当队列满时会直接丢弃日志,但是对性能提升极大 -->
        <neverBlock>true</neverBlock>
    </appender>
    <!--输出到文件:结束-->


    <!--滚动输出到文件(按照天保存):开始-->
    <!-- 将项目本次运行INFO日志同步输出到文件,按照每天生成日志文件,会自动拼接上一次日志 -->
    <appender name="APPENDER-ROLLINGFILEAPPENDER-INFO" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <!-- 过滤器,只记录 info 级别以上的日志 -->
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <level>INFO</level>
        </filter>
        <!--立即刷新,设置成false可以提高日志吞吐量-->
        <immediateFlush>false</immediateFlush>
        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
            <!-- 日志文件输出的文件名:
                %d:可以包含一个Java.text.SimpleDateFormat指定的时间格式
                %i:自增数字
            -->
            <fileNamePattern>${LOG_PATH}/${MACHINE_IP}/${VIRTUAL_IP}/HISTORY/${LOG_NAME}-info-%d{yyyy-MM-dd}-index%i.log</fileNamePattern>
            <!-- 日志文件保存历史数量:控制保留的归档文件的最大数量,如果超出数量就删除旧文件 -->
            <maxHistory>10</maxHistory>
            <!-- 文件大小超过100MB归档 -->
            <maxFileSize>20MB</maxFileSize>
        </rollingPolicy>
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <pattern>${FILE_LOG_PATTERN}</pattern>
            <charset>${ENCODING}</charset>
        </encoder>
    </appender>

    <!-- 将项目本次运行INFO日志异步输出到文件,按照每天生成日志文件,会自动拼接上一次日志 -->
    <appender name="ASYNC-APPENDER-ROLLINGFILEAPPENDER-INFO" class="ch.qos.logback.classic.AsyncAppender">
        <appender-ref ref="APPENDER-ROLLINGFILEAPPENDER-INFO" />
        <!-- 设置异步阻塞队列的大小,为了不丢失日志建议设置的大一些,单机压测时100000是没问题的,应该不用担心OOM -->
        <queueSize>10000</queueSize>
        <!-- 设置丢弃DEBUG、TRACE、INFO日志的阀值,不丢失 -->
        <discardingThreshold>0</discardingThreshold>
        <!-- 设置队列入队时非阻塞,当队列满时会直接丢弃日志,但是对性能提升极大 -->
        <neverBlock>true</neverBlock>
    </appender>

    <!-- 将项目本次运行DEBUG日志同步输出到文件,按照每天生成日志文件,会自动拼接上一次日志 -->
    <appender name="APPENDER-ROLLINGFILEAPPENDER-DEBUG" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <!-- 过滤器,只记录 info 级别以上的日志 -->
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <level>DEBUG</level>
        </filter>
        <!--立即刷新,设置成false可以提高日志吞吐量-->
        <immediateFlush>false</immediateFlush>
        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
            <!-- 日志文件输出的文件名:
                %d:可以包含一个Java.text.SimpleDateFormat指定的时间格式
                %i:自增数字
            -->
            <fileNamePattern>${LOG_PATH}/${MACHINE_IP}/${VIRTUAL_IP}/HISTORY/${LOG_NAME}-debug-%d{yyyy-MM-dd}-index%i.log</fileNamePattern>
            <!-- 日志文件保存历史数量:控制保留的归档文件的最大数量,如果超出数量就删除旧文件 -->
            <maxHistory>10</maxHistory>
            <!-- 文件大小超过100MB归档 -->
            <maxFileSize>20MB</maxFileSize>
        </rollingPolicy>
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <pattern>${FILE_LOG_PATTERN}</pattern>
            <charset>${ENCODING}</charset>
        </encoder>
    </appender>

    <!-- 将项目本次运行DEBUG日志异步输出到文件,按照每天生成日志文件,会自动拼接上一次日志 -->
    <appender name="ASYNC-APPENDER-ROLLINGFILEAPPENDER-DEBUG" class="ch.qos.logback.classic.AsyncAppender">
        <appender-ref ref="APPENDER-ROLLINGFILEAPPENDER-DEBUG" />
        <!-- 设置异步阻塞队列的大小,为了不丢失日志建议设置的大一些,单机压测时100000是没问题的,应该不用担心OOM -->
        <queueSize>10000</queueSize>
        <!-- 设置丢弃DEBUG、TRACE、INFO日志的阀值,不丢失 -->
        <discardingThreshold>0</discardingThreshold>
        <!-- 设置队列入队时非阻塞,当队列满时会直接丢弃日志,但是对性能提升极大 -->
        <neverBlock>true</neverBlock>
    </appender>

    <!-- 将项目本次运行ERROR日志同步输出到文件,按照每天生成日志文件,会自动拼接上一次日志 -->
    <appender name="APPENDER-ROLLINGFILEAPPENDER-ERROR" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <!-- 过滤器,只记录error级别的日志 -->
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>ERROR</level>
            <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>
        <!--立即刷新,设置成false可以提高日志吞吐量-->
        <immediateFlush>false</immediateFlush>
        <!-- 每天生成一个日志文件,保存30天的日志文件 -->
        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
            <!-- 日志文件输出的文件名:按天回滚 daily -->
            <fileNamePattern>${LOG_PATH}/${MACHINE_IP}/${VIRTUAL_IP}/HISTORY/${LOG_NAME}-error-%d{yyyy-MM-dd}-index%i.log</fileNamePattern>
            <!-- 日志文件保留天数 -->
            <maxHistory>10</maxHistory>
            <!-- 文件大小超过100MB归档 -->
            <maxFileSize>20MB</maxFileSize>
        </rollingPolicy>
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <pattern>${FILE_LOG_PATTERN}</pattern>
            <charset>utf8</charset>
        </encoder>
    </appender>

    <appender name="ASYNC-APPENDER-ROLLINGFILEAPPENDER-ERROR" class="ch.qos.logback.classic.AsyncAppender">
        <appender-ref ref="APPENDER-ROLLINGFILEAPPENDER-ERROR" />
        <!-- 设置异步阻塞队列的大小,为了不丢失日志建议设置的大一些,单机压测时100000是没问题的,应该不用担心OOM -->
        <queueSize>10000</queueSize>
        <!-- 设置丢弃DEBUG、TRACE、INFO日志的阀值,不丢失 -->
        <discardingThreshold>0</discardingThreshold>
        <!-- 设置队列入队时非阻塞,当队列满时会直接丢弃日志,但是对性能提升极大 -->
        <neverBlock>true</neverBlock>
    </appender>
    <!--滚动输出到文件(按照天保存):结束-->

    <!--输出到LOGSTASH:开始-->
    <!-- 将项目本次运行ERROR日志同步输出到文件,按照每天生成日志文件,会自动拼接上一次日志 -->
    <appender name="APPENDER-LOGSTASH" class="net.logstash.logback.appender.LogstashTcpSocketAppender">
        <!--  logstash服务器地址-->
        <destination>${LOGSTASH_HOST}</destination>
        <encoder class="net.logstash.logback.encoder.LoggingEventCompositeJsonEncoder">
            <providers>
                <pattern>
                    <pattern>
                        {
                        "appName":"${INDEX_NAME}",
                        "machineIp":"${MACHINE_IP}",
                        "virtualIp":"${VIRTUAL_IP}",
                        "serviceName":"${LOG_NAME}",
                        "timestamp": "%date{\"yyyy-MM-dd'T'HH:mm:ss,SSSZ\"}",
                        "logLevel":"%level",
                        "message":"%msg%n",
                        "traceId": "%X{X-B3-TraceId:-}",
                        "spanId": "%X{X-B3-SpanId:-}",
                        "spanExport": "%X{X-Span-Export:-}"
                        }
                    </pattern>
                </pattern>
            </providers>
        </encoder>
    </appender>
    <appender name="ASYNC-APPENDER-LOGSTASH" class="ch.qos.logback.classic.AsyncAppender">
        <appender-ref ref="APPENDER-LOGSTASH" />
        <!-- 设置异步阻塞队列的大小,为了不丢失日志建议设置的大一些,单机压测时100000是没问题的,应该不用担心OOM -->
        <queueSize>10000</queueSize>
        <!-- 设置丢弃DEBUG、TRACE、INFO日志的阀值,不丢失 -->
        <discardingThreshold>0</discardingThreshold>
        <!-- 设置队列入队时非阻塞,当队列满时会直接丢弃日志,但是对性能提升极大 -->
        <neverBlock>true</neverBlock>
    </appender>
    <!--输出到logstash:结束-->

    <!--
        开发环境日志级别为DEBUG
        level:用来设置打印级别
        五个常用打印级别从低至高依次为TRACE、DEBUG、INFO、WARN、ERROR
    -->
    <springProfile name="dev">
        <root>
            <!--输出到控制台-->
            <appender-ref ref="STDOUT"/>
            <!--异步非滚动输出到文件-->
            <appender-ref ref="ASYNC-APPENDER-FILEAPPENDER-INFO"/>
            <appender-ref ref="ASYNC-APPENDER-FILEAPPENDER-DEBUG"/>
            <appender-ref ref="ASYNC-APPENDER-FILEAPPENDER-ERROR"/>
            <!--异步滚动输出到文件:dev环境不开启-->
<!--            <appender-ref ref="ASYNC-APPENDER-ROLLINGFILEAPPENDER-INFO"/>-->
<!--            <appender-ref ref="ASYNC-APPENDER-ROLLINGFILEAPPENDER-DEBUG"/>-->
<!--            <appender-ref ref="ASYNC-APPENDER-ROLLINGFILEAPPENDER-ERROR"/>-->
            <!--异步滚动输出到logstash-->
            <appender-ref ref="ASYNC-APPENDER-LOGSTASH"/>
        </root>
    </springProfile>

    <!-- 测试环境日志级别为INFO -->
    <springProfile name="test">
        <root>
            <!--输出到控制台-->
            <appender-ref ref="STDOUT"/>
            <!--异步非滚动输出到文件-->
            <appender-ref ref="ASYNC-APPENDER-FILEAPPENDER-INFO"/>
            <appender-ref ref="ASYNC-APPENDER-FILEAPPENDER-DEBUG"/>
            <appender-ref ref="ASYNC-APPENDER-FILEAPPENDER-ERROR"/>
            <!--异步滚动输出到文件:test环境不开启-->
<!--            <appender-ref ref="ASYNC-APPENDER-ROLLINGFILEAPPENDER-INFO"/>-->
<!--            <appender-ref ref="ASYNC-APPENDER-ROLLINGFILEAPPENDER-DEBUG"/>-->
<!--            <appender-ref ref="ASYNC-APPENDER-ROLLINGFILEAPPENDER-ERROR"/>-->
            <!--异步滚动输出到logstash-->
            <appender-ref ref="ASYNC-APPENDER-LOGSTASH"/>
        </root>
    </springProfile>

    <!-- 生产环境日志级别为INFO -->
    <springProfile name="prod">
        <root>
            <!--输出到控制台-->
            <appender-ref ref="STDOUT"/>
            <!--异步非滚动输出到文件-->
            <appender-ref ref="ASYNC-APPENDER-FILEAPPENDER-INFO"/>
            <appender-ref ref="ASYNC-APPENDER-FILEAPPENDER-DEBUG"/>
            <appender-ref ref="ASYNC-APPENDER-FILEAPPENDER-ERROR"/>
            <!--异步滚动输出到文件-->
            <appender-ref ref="ASYNC-APPENDER-ROLLINGFILEAPPENDER-INFO"/>
            <appender-ref ref="ASYNC-APPENDER-ROLLINGFILEAPPENDER-DEBUG"/>
            <appender-ref ref="ASYNC-APPENDER-ROLLINGFILEAPPENDER-ERROR"/>
            <!--异步滚动输出到logstash-->
            <appender-ref ref="ASYNC-APPENDER-LOGSTASH"/>
        </root>
    </springProfile>

    <!-- rancher环境日志级别为INFO -->
    <springProfile name="rancher">
        <root>
            <!--输出到控制台-->
            <appender-ref ref="STDOUT"/>
            <!--异步非滚动输出到文件-->
            <appender-ref ref="ASYNC-APPENDER-FILEAPPENDER-INFO"/>
            <appender-ref ref="ASYNC-APPENDER-FILEAPPENDER-DEBUG"/>
            <appender-ref ref="ASYNC-APPENDER-FILEAPPENDER-ERROR"/>
            <!--异步滚动输出到文件-->
            <appender-ref ref="ASYNC-APPENDER-ROLLINGFILEAPPENDER-INFO"/>
            <appender-ref ref="ASYNC-APPENDER-ROLLINGFILEAPPENDER-DEBUG"/>
            <appender-ref ref="ASYNC-APPENDER-ROLLINGFILEAPPENDER-ERROR"/>
            <!--异步滚动输出到logstash-->
            <appender-ref ref="ASYNC-APPENDER-LOGSTASH"/>
        </root>
    </springProfile>
</configuration>

prod环境配置文件
application.yml
#设置spring项目运行的环境
spring:
  profiles:
    active: '@profile.active@'


application-prod.yml
server:
  port: 7005 #访问端口
spring:
  application:
    name: SPRINGCLOUD-BASIC-SAMPLE-REGISTER-CENTER-SINGLE-NODE7005-PROD  #注意:服务名不要出现_
  devtools: #热部署开关
    restart:
      enabled: true
# 将Client作为服务注册到SpringBootAdmin Server端,通过Server来监听项目的运行情况
  boot:
    admin:
      client:
        #因为eureka的配置先加载所以可以使用${eureka.instance.ip-address}这个来动态获取ip,虽然这个键值对配置在下面
        url: http://192.168.0.4:${server.port}
eureka:
  instance:
    hostname: 192.168.0.4
  client:
    register-with-eureka: true #不向注册中心注册自己
    fetch-registry: false #表示自己就是注册中心,我的职责就是维护实例,不需要去检索服务
    service-url:
      defaultZone: http://192.168.0.4:7005/eureka
  server:
    enable-self-preservation: true #是否开启自我保护,true:服务失效不直接剔除,false:服务失效直接剔除
    eviction-interval-timer-in-ms: 2000 #默认发送心跳的时间间隔,单位为ms

#配置文件修改说明-------------------------------------------------:开始
#注意:不同的部署环境需要修改的配置
#   1.${logback.path}  #修改日志存放位置,Linxu为/,Windows为\
#       修改原因: Linux和Windows目录结构不同
#配置文件修改说明-------------------------------------------------:结束

#自定义日志配置文件路径
logging:
  config: classpath:logback-custom.xml
  path: /logs #所有日志存放在位置,加上\方便Linux环境下配置
  level:
    root: info #全局日志输出级别

logback:
  log-name: ${spring.application.name}
  append: false #是否启用append(追加到已经存在日志文件尾部),true:重启项目会追加新日志到之前日志,false:重启项目会清空之前的日志
  immediate-flush: true #是否启用immediateFlush(立即刷新),true:重启项目自动追加,false:重启项目会情况之前的日志
  deploy-machine-ip: 192.168.0.4 #当前微服务所在部署机器ip

#logstash相关配置:开始
logstash:
  host: 192.168.0.4:5044 # logstash地址
  index: '@project.parent.artifactId@' # es中index名称
#logstash相关配置:结束

#actuator监控:开始
#通过下面的配置启用所有的监控端点,默认情况下,这些端点是禁用的;
management:
  endpoints:
    web:
      exposure:
        include: '*'
    enabled-by-default: true
  endpoint:
    health:
      show-details: always # 访问/actuator/health时,显示详细信息,而不是仅仅显示"status": "UP"
    # 日志文件路径:特别注意,此处无法配置日志文件路径,因为rancher会生成虚拟ip,这个虚拟ip是无法在这里获取的,
    #           但是虚拟ip是路径的一部分,所以这个路径无法拼接出来,所以这里无法配置日志文件路径
    #logfile:
    #  external-file:
#actuator监控:结束

logback-custom.xml
<?xml version="1.0" encoding="UTF-8"?>

<!--
    scan: 当此属性设置为true时,配置文件如果发生改变,将会被重新加载,默认值为true。
    scanPeriod: 设置监测配置文件是否有修改的时间间隔,如果没有给出时间单位,默认单位是毫秒。当scan为true时,此属性生效。默认的时间间隔为1分钟。
    debug: 当此属性设置为true时,将打印出logback内部日志信息,实时查看logback运行状态。默认值为false。
-->
<!-- 输出logback内部日志信息,每隔30s判断一下配置文件有没有更新,若更新,则重新加载 -->
<configuration scan="true" scanPeriod="30 seconds" debug="false">
    <!--从java代码中获取虚拟ip的值-->
    <!--获取当前微服务部署虚拟IP,如rancher为当前微服务分配的ip-->
    <define name="VIRTUAL_IP" class="org.openatom.springcloud.config.VirtualIpConfig"/>

    <!--从Spring容器中获取配置(Spring配置文件加载顺序:bootstrap.yml->logback.xml->application.yml)-->
    <!--获取当前微服务部署机器ip-->
    <springProperty name="MACHINE_IP" scope="context" source="logback.deploy-machine-ip"/>
    <!--应用名称-->
    <springProperty name="LOG_NAME" scope="context" source="logback.log-name"/>
    <!--是否启用append-->
    <springProperty name="IS_APPEND" scope="context" source="logback.append"/>
    <!--是否启用立即刷新-->
    <springProperty name="IS_IMMEDIATEFLUSH" scope="context" source="logback.immediate-flush"/>
    <springProperty name="LOG_PATH" scope="context" source="logging.path"/>
    <!--logstash地址-->
    <springProperty name="LOGSTASH_HOST" scope="context" source="logstash.host"/>
    <!--索引名称-->
    <springProperty name="INDEX_NAME" scope="context" source="logstash.index"/>


    <!-- name:变量的名称,可以随意起名,但建议名字要简明直译;value:变量的值;在配置文件中,我们可以用 ${} 的方式来使用,将变量引入到其他节点中去。-->
    <!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度 %msg:日志消息,%n是换行符-->
    <!--控制台日志输出预选样式-->
    <property name="CONSOLE_LOG_PATTERN_1" value="%red(%d{yyyy-MM-dd HH:mm:ss.SSS}) %green([%thread]) [machineIp:${MACHINE_IP} virtualIp:${VIRTUAL_IP}] [TraceId:%X{X-B3-TraceId:-} SpanId:%X{X-B3-SpanId:-} %highlight(%-5level) %boldMagenta(%logger{10}): %cyan(%msg%n)"/>
    <property name="CONSOLE_LOG_PATTERN_2" value="%yellow(%date{yyyy-MM-dd HH:mm:ss}) [machineIp:${MACHINE_IP} virtualIp:${VIRTUAL_IP}] [TraceId:%X{X-B3-TraceId:-} SpanId:%X{X-B3-SpanId:-} %highlight([%-5level]) %green(%logger) %msg%n"/>
    <property name="CONSOLE_LOG_PATTERN_3" value="%date{yyyy-MM-dd HH:mm:ss} [machineIp:${MACHINE_IP} virtualIp:${VIRTUAL_IP}] [TraceId:%X{X-B3-TraceId:-} SpanId:%X{X-B3-SpanId:-} Span-Export:%X{X-Span-Export:-}]  %green(%-5level) %boldMagenta(${PID:-}) -- [%+20thread] %cyan(%logger{20}) %line       : %msg%n"/>
    <!--文件中日志输出预选样式-->
    <property name="FILE_LOG_PATTERN_1" value="%d{yyyyMMdd:HH:mm:ss.SSS} [machineIp:${MACHINE_IP} virtualIp:${VIRTUAL_IP}] [TraceId:%X{X-B3-TraceId:-} SpanId:%X{X-B3-SpanId:-} [%thread] %-5level  %msg%n"/>

    <!--控制台日志输出格式-->
    <property name="CONSOLE_LOG_PATTERN" value="${CONSOLE_LOG_PATTERN_3}"/>
    <!--文件中日志输出格式-->
    <property name="FILE_LOG_PATTERN" value="${FILE_LOG_PATTERN_1}"/>
    <!--日志名称-->
    <!--定义默认日志输出级别-->
    <property name="LOG_OUTPUT_LEVEL" value="${LOG_LEVEL}" />
    <!--定义默认日志输出编码-->
    <property name="ENCODING" value="UTF-8" />

    <!-- 控制台输出:开始 -->
    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
        <!-- 用来设置日志的输入格式,使用“%+转换符”的方式,如果要输出”%”则必须使用”\”进行转义。-->
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <!-- 格式化输出:https://logback.qos.ch/manual/layouts.html
                 %d 表示日期,
                 %thread 表示线程名,
                 %level 日志级别从左显示5个字符宽度,
                 %t 线程名
                 %file:%line 文件名+行号,
                 %m 日志消息,%n是换行符
                 %X{traceId}:自定义设置的参数,后面会说。
            -->
            <pattern>${CONSOLE_LOG_PATTERN}</pattern>
            <charset>${ENCODING}</charset>
        </encoder>
    </appender>
    <!-- 控制台输出:结束 -->

    <!--输出到文件:开始-->
    <!-- 将项目本次运行INFO日志同步输出到文件,会自动清空文件中上一次的日志 -->
    <appender name="APPENDER-FILEAPPENDER-INFO" class="ch.qos.logback.core.FileAppender">
        <!-- 过滤器,只记录 info 级别以上的日志 -->
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <level>INFO</level>
        </filter>
        <!-- 写入的日志文件名,可以使相对目录也可以是绝对目录,如果上级目录不存在则自动创建 -->
        <file>${LOG_PATH}/${MACHINE_IP}/${VIRTUAL_IP}/${LOG_NAME}-info.log</file>
        <!-- 如果为true表示日志被追加到文件结尾,如果是false表示清空文件 -->
        <append>${IS_APPEND}</append>
        <!--立即刷新,设置成false可以提高日志吞吐量-->
        <immediateFlush>${IS_IMMEDIATEFLUSH}</immediateFlush>
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <pattern>${FILE_LOG_PATTERN}</pattern>
            <charset>${ENCODING}</charset>
        </encoder>
    </appender>

    <!-- 将项目本次运行INFO日志异步输出到文件,会自动清空文件中上一次的日志 -->
    <appender name="ASYNC-APPENDER-FILEAPPENDER-INFO" class="ch.qos.logback.classic.AsyncAppender">
        <appender-ref ref="APPENDER-FILEAPPENDER-INFO" />
        <!-- 设置异步阻塞队列的大小,为了不丢失日志建议设置的大一些,单机压测时100000是没问题的,应该不用担心OOM -->
        <queueSize>10000</queueSize>
        <!-- 设置丢弃DEBUG、TRACE、INFO日志的阀值,不丢失 -->
        <discardingThreshold>0</discardingThreshold>
        <!-- 设置队列入队时非阻塞,当队列满时会直接丢弃日志,但是对性能提升极大 -->
        <neverBlock>${IS_IMMEDIATEFLUSH}</neverBlock>
    </appender>

    <!-- 将项目本次运行DEBUG日志同步输出到文件,会自动清空文件中上一次的日志 -->
    <appender name="APPENDER-FILEAPPENDER-DEBUG" class="ch.qos.logback.core.FileAppender">
        <!-- 过滤器,只记录 info 级别以上的日志 -->
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <level>DEBUG</level>
        </filter>
        <!-- 写入的日志文件名,可以使相对目录也可以是绝对目录,如果上级目录不存在则自动创建 -->
        <file>${LOG_PATH}/${MACHINE_IP}/${VIRTUAL_IP}/${LOG_NAME}-debug.log</file>
        <!-- 如果为true表示日志被追加到文件结尾,如果是false表示清空文件 -->
        <append>${IS_APPEND}</append>
        <!--立即刷新,设置成false可以提高日志吞吐量-->
        <immediateFlush>true</immediateFlush>
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <pattern>${FILE_LOG_PATTERN}</pattern>
            <charset>${ENCODING}</charset>
        </encoder>
    </appender>

    <!-- 将项目本次运行DEBUG日志异步输出到文件,会自动清空文件中上一次的日志 -->
    <appender name="ASYNC-APPENDER-FILEAPPENDER-DEBUG" class="ch.qos.logback.classic.AsyncAppender">
        <appender-ref ref="APPENDER-FILEAPPENDER-DEBUG" />
        <!-- 设置异步阻塞队列的大小,为了不丢失日志建议设置的大一些,单机压测时100000是没问题的,应该不用担心OOM -->
        <queueSize>10000</queueSize>
        <!-- 设置丢弃DEBUG、TRACE、INFO日志的阀值,不丢失 -->
        <discardingThreshold>0</discardingThreshold>
        <!-- 设置队列入队时非阻塞,当队列满时会直接丢弃日志,但是对性能提升极大 -->
        <neverBlock>true</neverBlock>
    </appender>

    <!-- 将项目本次运行ERROR日志同步输出到文件,会自动清空文件中上一次的日志 -->
    <appender name="APPENDER-FILEAPPENDER-ERROR" class="ch.qos.logback.core.FileAppender">
        <!-- 过滤器,只记录 info 级别以上的日志 -->
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <level>DEBUG</level>
        </filter>
        <!-- 写入的日志文件名,可以使相对目录也可以是绝对目录,如果上级目录不存在则自动创建 -->
        <file>${LOG_PATH}/${MACHINE_IP}/${VIRTUAL_IP}/${LOG_NAME}-error.log</file>
        <!-- 如果为true表示日志被追加到文件结尾,如果是false表示清空文件 -->
        <append>${IS_APPEND}</append>
        <!--立即刷新,设置成false可以提高日志吞吐量-->
        <immediateFlush>${IS_IMMEDIATEFLUSH}</immediateFlush>
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <pattern>${FILE_LOG_PATTERN}</pattern>
            <charset>${ENCODING}</charset>
        </encoder>
    </appender>

    <!-- 将项目本次运行ERROR日志异步输出到文件,会自动清空文件中上一次的日志 -->
    <appender name="ASYNC-APPENDER-FILEAPPENDER-ERROR" class="ch.qos.logback.classic.AsyncAppender">
        <appender-ref ref="APPENDER-FILEAPPENDER-ERROR" />
        <!-- 设置异步阻塞队列的大小,为了不丢失日志建议设置的大一些,单机压测时100000是没问题的,应该不用担心OOM -->
        <queueSize>10000</queueSize>
        <!-- 设置丢弃DEBUG、TRACE、INFO日志的阀值,不丢失 -->
        <discardingThreshold>0</discardingThreshold>
        <!-- 设置队列入队时非阻塞,当队列满时会直接丢弃日志,但是对性能提升极大 -->
        <neverBlock>true</neverBlock>
    </appender>
    <!--输出到文件:结束-->


    <!--滚动输出到文件(按照天保存):开始-->
    <!-- 将项目本次运行INFO日志同步输出到文件,按照每天生成日志文件,会自动拼接上一次日志 -->
    <appender name="APPENDER-ROLLINGFILEAPPENDER-INFO" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <!-- 过滤器,只记录 info 级别以上的日志 -->
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <level>INFO</level>
        </filter>
        <!--立即刷新,设置成false可以提高日志吞吐量-->
        <immediateFlush>false</immediateFlush>
        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
            <!-- 日志文件输出的文件名:
                %d:可以包含一个Java.text.SimpleDateFormat指定的时间格式
                %i:自增数字
            -->
            <fileNamePattern>${LOG_PATH}/${MACHINE_IP}/${VIRTUAL_IP}/HISTORY/${LOG_NAME}-info-%d{yyyy-MM-dd}-index%i.log</fileNamePattern>
            <!-- 日志文件保存历史数量:控制保留的归档文件的最大数量,如果超出数量就删除旧文件 -->
            <maxHistory>10</maxHistory>
            <!-- 文件大小超过100MB归档 -->
            <maxFileSize>20MB</maxFileSize>
        </rollingPolicy>
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <pattern>${FILE_LOG_PATTERN}</pattern>
            <charset>${ENCODING}</charset>
        </encoder>
    </appender>

    <!-- 将项目本次运行INFO日志异步输出到文件,按照每天生成日志文件,会自动拼接上一次日志 -->
    <appender name="ASYNC-APPENDER-ROLLINGFILEAPPENDER-INFO" class="ch.qos.logback.classic.AsyncAppender">
        <appender-ref ref="APPENDER-ROLLINGFILEAPPENDER-INFO" />
        <!-- 设置异步阻塞队列的大小,为了不丢失日志建议设置的大一些,单机压测时100000是没问题的,应该不用担心OOM -->
        <queueSize>10000</queueSize>
        <!-- 设置丢弃DEBUG、TRACE、INFO日志的阀值,不丢失 -->
        <discardingThreshold>0</discardingThreshold>
        <!-- 设置队列入队时非阻塞,当队列满时会直接丢弃日志,但是对性能提升极大 -->
        <neverBlock>true</neverBlock>
    </appender>

    <!-- 将项目本次运行DEBUG日志同步输出到文件,按照每天生成日志文件,会自动拼接上一次日志 -->
    <appender name="APPENDER-ROLLINGFILEAPPENDER-DEBUG" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <!-- 过滤器,只记录 info 级别以上的日志 -->
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <level>DEBUG</level>
        </filter>
        <!--立即刷新,设置成false可以提高日志吞吐量-->
        <immediateFlush>false</immediateFlush>
        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
            <!-- 日志文件输出的文件名:
                %d:可以包含一个Java.text.SimpleDateFormat指定的时间格式
                %i:自增数字
            -->
            <fileNamePattern>${LOG_PATH}/${MACHINE_IP}/${VIRTUAL_IP}/HISTORY/${LOG_NAME}-debug-%d{yyyy-MM-dd}-index%i.log</fileNamePattern>
            <!-- 日志文件保存历史数量:控制保留的归档文件的最大数量,如果超出数量就删除旧文件 -->
            <maxHistory>10</maxHistory>
            <!-- 文件大小超过100MB归档 -->
            <maxFileSize>20MB</maxFileSize>
        </rollingPolicy>
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <pattern>${FILE_LOG_PATTERN}</pattern>
            <charset>${ENCODING}</charset>
        </encoder>
    </appender>

    <!-- 将项目本次运行DEBUG日志异步输出到文件,按照每天生成日志文件,会自动拼接上一次日志 -->
    <appender name="ASYNC-APPENDER-ROLLINGFILEAPPENDER-DEBUG" class="ch.qos.logback.classic.AsyncAppender">
        <appender-ref ref="APPENDER-ROLLINGFILEAPPENDER-DEBUG" />
        <!-- 设置异步阻塞队列的大小,为了不丢失日志建议设置的大一些,单机压测时100000是没问题的,应该不用担心OOM -->
        <queueSize>10000</queueSize>
        <!-- 设置丢弃DEBUG、TRACE、INFO日志的阀值,不丢失 -->
        <discardingThreshold>0</discardingThreshold>
        <!-- 设置队列入队时非阻塞,当队列满时会直接丢弃日志,但是对性能提升极大 -->
        <neverBlock>true</neverBlock>
    </appender>

    <!-- 将项目本次运行ERROR日志同步输出到文件,按照每天生成日志文件,会自动拼接上一次日志 -->
    <appender name="APPENDER-ROLLINGFILEAPPENDER-ERROR" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <!-- 过滤器,只记录error级别的日志 -->
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>ERROR</level>
            <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>
        <!--立即刷新,设置成false可以提高日志吞吐量-->
        <immediateFlush>false</immediateFlush>
        <!-- 每天生成一个日志文件,保存30天的日志文件 -->
        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
            <!-- 日志文件输出的文件名:按天回滚 daily -->
            <fileNamePattern>${LOG_PATH}/${MACHINE_IP}/${VIRTUAL_IP}/HISTORY/${LOG_NAME}-error-%d{yyyy-MM-dd}-index%i.log</fileNamePattern>
            <!-- 日志文件保留天数 -->
            <maxHistory>10</maxHistory>
            <!-- 文件大小超过100MB归档 -->
            <maxFileSize>20MB</maxFileSize>
        </rollingPolicy>
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <pattern>${FILE_LOG_PATTERN}</pattern>
            <charset>utf8</charset>
        </encoder>
    </appender>

    <appender name="ASYNC-APPENDER-ROLLINGFILEAPPENDER-ERROR" class="ch.qos.logback.classic.AsyncAppender">
        <appender-ref ref="APPENDER-ROLLINGFILEAPPENDER-ERROR" />
        <!-- 设置异步阻塞队列的大小,为了不丢失日志建议设置的大一些,单机压测时100000是没问题的,应该不用担心OOM -->
        <queueSize>10000</queueSize>
        <!-- 设置丢弃DEBUG、TRACE、INFO日志的阀值,不丢失 -->
        <discardingThreshold>0</discardingThreshold>
        <!-- 设置队列入队时非阻塞,当队列满时会直接丢弃日志,但是对性能提升极大 -->
        <neverBlock>true</neverBlock>
    </appender>
    <!--滚动输出到文件(按照天保存):结束-->

    <!--输出到LOGSTASH:开始-->
    <!-- 将项目本次运行ERROR日志同步输出到文件,按照每天生成日志文件,会自动拼接上一次日志 -->
    <appender name="APPENDER-LOGSTASH" class="net.logstash.logback.appender.LogstashTcpSocketAppender">
        <!--  logstash服务器地址-->
        <destination>${LOGSTASH_HOST}</destination>
        <encoder class="net.logstash.logback.encoder.LoggingEventCompositeJsonEncoder">
            <providers>
                <pattern>
                    <pattern>
                        {
                        "appName":"${INDEX_NAME}",
                        "machineIp":"${MACHINE_IP}",
                        "virtualIp":"${VIRTUAL_IP}",
                        "serviceName":"${LOG_NAME}",
                        "timestamp": "%date{\"yyyy-MM-dd'T'HH:mm:ss,SSSZ\"}",
                        "logLevel":"%level",
                        "message":"%msg%n",
                        "traceId": "%X{X-B3-TraceId:-}",
                        "spanId": "%X{X-B3-SpanId:-}",
                        "spanExport": "%X{X-Span-Export:-}"
                        }
                    </pattern>
                </pattern>
            </providers>
        </encoder>
    </appender>
    <appender name="ASYNC-APPENDER-LOGSTASH" class="ch.qos.logback.classic.AsyncAppender">
        <appender-ref ref="APPENDER-LOGSTASH" />
        <!-- 设置异步阻塞队列的大小,为了不丢失日志建议设置的大一些,单机压测时100000是没问题的,应该不用担心OOM -->
        <queueSize>10000</queueSize>
        <!-- 设置丢弃DEBUG、TRACE、INFO日志的阀值,不丢失 -->
        <discardingThreshold>0</discardingThreshold>
        <!-- 设置队列入队时非阻塞,当队列满时会直接丢弃日志,但是对性能提升极大 -->
        <neverBlock>true</neverBlock>
    </appender>
    <!--输出到logstash:结束-->

    <!--
        开发环境日志级别为DEBUG
        level:用来设置打印级别
        五个常用打印级别从低至高依次为TRACE、DEBUG、INFO、WARN、ERROR
    -->
    <springProfile name="dev">
        <root>
            <!--输出到控制台-->
            <appender-ref ref="STDOUT"/>
            <!--异步非滚动输出到文件-->
            <appender-ref ref="ASYNC-APPENDER-FILEAPPENDER-INFO"/>
            <appender-ref ref="ASYNC-APPENDER-FILEAPPENDER-DEBUG"/>
            <appender-ref ref="ASYNC-APPENDER-FILEAPPENDER-ERROR"/>
            <!--异步滚动输出到文件:dev环境不开启-->
<!--            <appender-ref ref="ASYNC-APPENDER-ROLLINGFILEAPPENDER-INFO"/>-->
<!--            <appender-ref ref="ASYNC-APPENDER-ROLLINGFILEAPPENDER-DEBUG"/>-->
<!--            <appender-ref ref="ASYNC-APPENDER-ROLLINGFILEAPPENDER-ERROR"/>-->
            <!--异步滚动输出到logstash-->
            <appender-ref ref="ASYNC-APPENDER-LOGSTASH"/>
        </root>
    </springProfile>

    <!-- 测试环境日志级别为INFO -->
    <springProfile name="test">
        <root>
            <!--输出到控制台-->
            <appender-ref ref="STDOUT"/>
            <!--异步非滚动输出到文件-->
            <appender-ref ref="ASYNC-APPENDER-FILEAPPENDER-INFO"/>
            <appender-ref ref="ASYNC-APPENDER-FILEAPPENDER-DEBUG"/>
            <appender-ref ref="ASYNC-APPENDER-FILEAPPENDER-ERROR"/>
            <!--异步滚动输出到文件:test环境不开启-->
<!--            <appender-ref ref="ASYNC-APPENDER-ROLLINGFILEAPPENDER-INFO"/>-->
<!--            <appender-ref ref="ASYNC-APPENDER-ROLLINGFILEAPPENDER-DEBUG"/>-->
<!--            <appender-ref ref="ASYNC-APPENDER-ROLLINGFILEAPPENDER-ERROR"/>-->
            <!--异步滚动输出到logstash-->
            <appender-ref ref="ASYNC-APPENDER-LOGSTASH"/>
        </root>
    </springProfile>

    <!-- 生产环境日志级别为INFO -->
    <springProfile name="prod">
        <root>
            <!--输出到控制台-->
            <appender-ref ref="STDOUT"/>
            <!--异步非滚动输出到文件-->
            <appender-ref ref="ASYNC-APPENDER-FILEAPPENDER-INFO"/>
            <appender-ref ref="ASYNC-APPENDER-FILEAPPENDER-DEBUG"/>
            <appender-ref ref="ASYNC-APPENDER-FILEAPPENDER-ERROR"/>
            <!--异步滚动输出到文件-->
            <appender-ref ref="ASYNC-APPENDER-ROLLINGFILEAPPENDER-INFO"/>
            <appender-ref ref="ASYNC-APPENDER-ROLLINGFILEAPPENDER-DEBUG"/>
            <appender-ref ref="ASYNC-APPENDER-ROLLINGFILEAPPENDER-ERROR"/>
            <!--异步滚动输出到logstash-->
            <appender-ref ref="ASYNC-APPENDER-LOGSTASH"/>
        </root>
    </springProfile>

    <!-- rancher环境日志级别为INFO -->
    <springProfile name="rancher">
        <root>
            <!--输出到控制台-->
            <appender-ref ref="STDOUT"/>
            <!--异步非滚动输出到文件-->
            <appender-ref ref="ASYNC-APPENDER-FILEAPPENDER-INFO"/>
            <appender-ref ref="ASYNC-APPENDER-FILEAPPENDER-DEBUG"/>
            <appender-ref ref="ASYNC-APPENDER-FILEAPPENDER-ERROR"/>
            <!--异步滚动输出到文件-->
            <appender-ref ref="ASYNC-APPENDER-ROLLINGFILEAPPENDER-INFO"/>
            <appender-ref ref="ASYNC-APPENDER-ROLLINGFILEAPPENDER-DEBUG"/>
            <appender-ref ref="ASYNC-APPENDER-ROLLINGFILEAPPENDER-ERROR"/>
            <!--异步滚动输出到logstash-->
            <appender-ref ref="ASYNC-APPENDER-LOGSTASH"/>
        </root>
    </springProfile>
</configuration>

rancher环境配置文件
application.yml
#设置spring项目运行的环境
spring:
  profiles:
    active: '@profile.active@'


application-rancher.yml
server:
  port: 7005 #访问端口
spring:
  application:
    name: SPRINGCLOUD-BASIC-SAMPLE-REGISTER-CENTER-SINGLE-NODE7005-RANCHER  #注意:服务名不要出现_
  devtools: #热部署开关
    restart:
      enabled: true
# 将Client作为服务注册到SpringBootAdmin Server端,通过Server来监听项目的运行情况
  boot:
    admin:
      client:
        #因为eureka的配置先加载所以可以使用${eureka.instance.ip-address}这个来动态获取ip,虽然这个键值对配置在下面
        url: http://192.168.0.4:${server.port}
eureka:
  instance:
    hostname: 192.168.0.4
  client:
    register-with-eureka: true #不向注册中心注册自己
    fetch-registry: false #表示自己就是注册中心,我的职责就是维护实例,不需要去检索服务
    service-url:
      defaultZone: http://192.168.0.4:7005/eureka
  server:
    enable-self-preservation: true #是否开启自我保护,true:服务失效不直接剔除,false:服务失效直接剔除
    eviction-interval-timer-in-ms: 2000 #默认发送心跳的时间间隔,单位为ms

#配置文件修改说明-------------------------------------------------:开始
#注意:不同的部署环境需要修改的配置
#   1.${logback.path}  #修改日志存放位置,Linxu为/,Windows为\
#       修改原因: Linux和Windows目录结构不同
#配置文件修改说明-------------------------------------------------:结束

#自定义日志配置文件路径
logging:
  config: classpath:logback-custom.xml
  path: /logs #所有日志存放在位置,加上\方便Linux环境下配置
  level:
    root: info #全局日志输出级别

logback:
  log-name: ${spring.application.name}
  append: false #是否启用append(追加到已经存在日志文件尾部),true:重启项目会追加新日志到之前日志,false:重启项目会清空之前的日志
  immediate-flush: true #是否启用immediateFlush(立即刷新),true:重启项目自动追加,false:重启项目会情况之前的日志
  deploy-machine-ip: 192.168.0.4 #当前微服务所在部署机器ip

#logstash相关配置:开始
logstash:
  enable: true #默认为false
  host: 192.168.0.4:5044 # logstash地址
  index: '@project.parent.artifactId@' # es中index名称
#logstash相关配置:结束

#actuator监控:开始
#通过下面的配置启用所有的监控端点,默认情况下,这些端点是禁用的;
management:
  endpoints:
    web:
      exposure:
        include: '*'
    enabled-by-default: true
  endpoint:
    health:
      show-details: always # 访问/actuator/health时,显示详细信息,而不是仅仅显示"status": "UP"
    # 日志文件路径:特别注意,此处无法配置日志文件路径,因为rancher会生成虚拟ip,这个虚拟ip是无法在这里获取的,
    #           但是虚拟ip是路径的一部分,所以这个路径无法拼接出来,所以这里无法配置日志文件路径
    #logfile:
    #  external-file:
#actuator监控:结束

logback-custom.xml
<?xml version="1.0" encoding="UTF-8"?>

<!--
    scan: 当此属性设置为true时,配置文件如果发生改变,将会被重新加载,默认值为true。
    scanPeriod: 设置监测配置文件是否有修改的时间间隔,如果没有给出时间单位,默认单位是毫秒。当scan为true时,此属性生效。默认的时间间隔为1分钟。
    debug: 当此属性设置为true时,将打印出logback内部日志信息,实时查看logback运行状态。默认值为false。
-->
<!-- 输出logback内部日志信息,每隔30s判断一下配置文件有没有更新,若更新,则重新加载 -->
<configuration scan="true" scanPeriod="30 seconds" debug="false">
    <!--从java代码中获取虚拟ip的值-->
    <!--获取当前微服务部署虚拟IP,如rancher为当前微服务分配的ip-->
    <define name="VIRTUAL_IP" class="org.openatom.springcloud.config.VirtualIpConfig"/>

    <!--从Spring容器中获取配置(Spring配置文件加载顺序:bootstrap.yml->logback.xml->application.yml)-->
    <!--获取当前微服务部署机器ip-->
    <springProperty name="MACHINE_IP" scope="context" source="logback.deploy-machine-ip"/>
    <!--应用名称-->
    <springProperty name="LOG_NAME" scope="context" source="logback.log-name"/>
    <!--是否启用append-->
    <springProperty name="IS_APPEND" scope="context" source="logback.append"/>
    <!--是否启用立即刷新-->
    <springProperty name="IS_IMMEDIATEFLUSH" scope="context" source="logback.immediate-flush"/>
    <springProperty name="LOG_PATH" scope="context" source="logging.path"/>
    <!--logstash地址-->
    <springProperty name="LOGSTASH_HOST" scope="context" source="logstash.host"/>
    <!--索引名称-->
    <springProperty name="INDEX_NAME" scope="context" source="logstash.index"/>


    <!-- name:变量的名称,可以随意起名,但建议名字要简明直译;value:变量的值;在配置文件中,我们可以用 ${} 的方式来使用,将变量引入到其他节点中去。-->
    <!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度 %msg:日志消息,%n是换行符-->
    <!--控制台日志输出预选样式-->
    <property name="CONSOLE_LOG_PATTERN_1" value="%red(%d{yyyy-MM-dd HH:mm:ss.SSS}) %green([%thread]) [machineIp:${MACHINE_IP} virtualIp:${VIRTUAL_IP}] [TraceId:%X{X-B3-TraceId:-} SpanId:%X{X-B3-SpanId:-} %highlight(%-5level) %boldMagenta(%logger{10}): %cyan(%msg%n)"/>
    <property name="CONSOLE_LOG_PATTERN_2" value="%yellow(%date{yyyy-MM-dd HH:mm:ss}) [machineIp:${MACHINE_IP} virtualIp:${VIRTUAL_IP}] [TraceId:%X{X-B3-TraceId:-} SpanId:%X{X-B3-SpanId:-} %highlight([%-5level]) %green(%logger) %msg%n"/>
    <property name="CONSOLE_LOG_PATTERN_3" value="%date{yyyy-MM-dd HH:mm:ss} [machineIp:${MACHINE_IP} virtualIp:${VIRTUAL_IP}] [TraceId:%X{X-B3-TraceId:-} SpanId:%X{X-B3-SpanId:-} Span-Export:%X{X-Span-Export:-}]  %green(%-5level) %boldMagenta(${PID:-}) -- [%+20thread] %cyan(%logger{20}) %line       : %msg%n"/>
    <!--文件中日志输出预选样式-->
    <property name="FILE_LOG_PATTERN_1" value="%d{yyyyMMdd:HH:mm:ss.SSS} [machineIp:${MACHINE_IP} virtualIp:${VIRTUAL_IP}] [TraceId:%X{X-B3-TraceId:-} SpanId:%X{X-B3-SpanId:-} [%thread] %-5level  %msg%n"/>

    <!--控制台日志输出格式-->
    <property name="CONSOLE_LOG_PATTERN" value="${CONSOLE_LOG_PATTERN_3}"/>
    <!--文件中日志输出格式-->
    <property name="FILE_LOG_PATTERN" value="${FILE_LOG_PATTERN_1}"/>
    <!--日志名称-->
    <!--定义默认日志输出级别-->
    <property name="LOG_OUTPUT_LEVEL" value="${LOG_LEVEL}" />
    <!--定义默认日志输出编码-->
    <property name="ENCODING" value="UTF-8" />

    <!-- 控制台输出:开始 -->
    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
        <!-- 用来设置日志的输入格式,使用“%+转换符”的方式,如果要输出”%”则必须使用”\”进行转义。-->
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <!-- 格式化输出:https://logback.qos.ch/manual/layouts.html
                 %d 表示日期,
                 %thread 表示线程名,
                 %level 日志级别从左显示5个字符宽度,
                 %t 线程名
                 %file:%line 文件名+行号,
                 %m 日志消息,%n是换行符
                 %X{traceId}:自定义设置的参数,后面会说。
            -->
            <pattern>${CONSOLE_LOG_PATTERN}</pattern>
            <charset>${ENCODING}</charset>
        </encoder>
    </appender>
    <!-- 控制台输出:结束 -->

    <!--输出到文件:开始-->
    <!-- 将项目本次运行INFO日志同步输出到文件,会自动清空文件中上一次的日志 -->
    <appender name="APPENDER-FILEAPPENDER-INFO" class="ch.qos.logback.core.FileAppender">
        <!-- 过滤器,只记录 info 级别以上的日志 -->
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <level>INFO</level>
        </filter>
        <!-- 写入的日志文件名,可以使相对目录也可以是绝对目录,如果上级目录不存在则自动创建 -->
        <file>${LOG_PATH}/${MACHINE_IP}/${VIRTUAL_IP}/${LOG_NAME}-info.log</file>
        <!-- 如果为true表示日志被追加到文件结尾,如果是false表示清空文件 -->
        <append>${IS_APPEND}</append>
        <!--立即刷新,设置成false可以提高日志吞吐量-->
        <immediateFlush>${IS_IMMEDIATEFLUSH}</immediateFlush>
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <pattern>${FILE_LOG_PATTERN}</pattern>
            <charset>${ENCODING}</charset>
        </encoder>
    </appender>

    <!-- 将项目本次运行INFO日志异步输出到文件,会自动清空文件中上一次的日志 -->
    <appender name="ASYNC-APPENDER-FILEAPPENDER-INFO" class="ch.qos.logback.classic.AsyncAppender">
        <appender-ref ref="APPENDER-FILEAPPENDER-INFO" />
        <!-- 设置异步阻塞队列的大小,为了不丢失日志建议设置的大一些,单机压测时100000是没问题的,应该不用担心OOM -->
        <queueSize>10000</queueSize>
        <!-- 设置丢弃DEBUG、TRACE、INFO日志的阀值,不丢失 -->
        <discardingThreshold>0</discardingThreshold>
        <!-- 设置队列入队时非阻塞,当队列满时会直接丢弃日志,但是对性能提升极大 -->
        <neverBlock>${IS_IMMEDIATEFLUSH}</neverBlock>
    </appender>

    <!-- 将项目本次运行DEBUG日志同步输出到文件,会自动清空文件中上一次的日志 -->
    <appender name="APPENDER-FILEAPPENDER-DEBUG" class="ch.qos.logback.core.FileAppender">
        <!-- 过滤器,只记录 info 级别以上的日志 -->
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <level>DEBUG</level>
        </filter>
        <!-- 写入的日志文件名,可以使相对目录也可以是绝对目录,如果上级目录不存在则自动创建 -->
        <file>${LOG_PATH}/${MACHINE_IP}/${VIRTUAL_IP}/${LOG_NAME}-debug.log</file>
        <!-- 如果为true表示日志被追加到文件结尾,如果是false表示清空文件 -->
        <append>${IS_APPEND}</append>
        <!--立即刷新,设置成false可以提高日志吞吐量-->
        <immediateFlush>true</immediateFlush>
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <pattern>${FILE_LOG_PATTERN}</pattern>
            <charset>${ENCODING}</charset>
        </encoder>
    </appender>

    <!-- 将项目本次运行DEBUG日志异步输出到文件,会自动清空文件中上一次的日志 -->
    <appender name="ASYNC-APPENDER-FILEAPPENDER-DEBUG" class="ch.qos.logback.classic.AsyncAppender">
        <appender-ref ref="APPENDER-FILEAPPENDER-DEBUG" />
        <!-- 设置异步阻塞队列的大小,为了不丢失日志建议设置的大一些,单机压测时100000是没问题的,应该不用担心OOM -->
        <queueSize>10000</queueSize>
        <!-- 设置丢弃DEBUG、TRACE、INFO日志的阀值,不丢失 -->
        <discardingThreshold>0</discardingThreshold>
        <!-- 设置队列入队时非阻塞,当队列满时会直接丢弃日志,但是对性能提升极大 -->
        <neverBlock>true</neverBlock>
    </appender>

    <!-- 将项目本次运行ERROR日志同步输出到文件,会自动清空文件中上一次的日志 -->
    <appender name="APPENDER-FILEAPPENDER-ERROR" class="ch.qos.logback.core.FileAppender">
        <!-- 过滤器,只记录 info 级别以上的日志 -->
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <level>DEBUG</level>
        </filter>
        <!-- 写入的日志文件名,可以使相对目录也可以是绝对目录,如果上级目录不存在则自动创建 -->
        <file>${LOG_PATH}/${MACHINE_IP}/${VIRTUAL_IP}/${LOG_NAME}-error.log</file>
        <!-- 如果为true表示日志被追加到文件结尾,如果是false表示清空文件 -->
        <append>${IS_APPEND}</append>
        <!--立即刷新,设置成false可以提高日志吞吐量-->
        <immediateFlush>${IS_IMMEDIATEFLUSH}</immediateFlush>
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <pattern>${FILE_LOG_PATTERN}</pattern>
            <charset>${ENCODING}</charset>
        </encoder>
    </appender>

    <!-- 将项目本次运行ERROR日志异步输出到文件,会自动清空文件中上一次的日志 -->
    <appender name="ASYNC-APPENDER-FILEAPPENDER-ERROR" class="ch.qos.logback.classic.AsyncAppender">
        <appender-ref ref="APPENDER-FILEAPPENDER-ERROR" />
        <!-- 设置异步阻塞队列的大小,为了不丢失日志建议设置的大一些,单机压测时100000是没问题的,应该不用担心OOM -->
        <queueSize>10000</queueSize>
        <!-- 设置丢弃DEBUG、TRACE、INFO日志的阀值,不丢失 -->
        <discardingThreshold>0</discardingThreshold>
        <!-- 设置队列入队时非阻塞,当队列满时会直接丢弃日志,但是对性能提升极大 -->
        <neverBlock>true</neverBlock>
    </appender>
    <!--输出到文件:结束-->


    <!--滚动输出到文件(按照天保存):开始-->
    <!-- 将项目本次运行INFO日志同步输出到文件,按照每天生成日志文件,会自动拼接上一次日志 -->
    <appender name="APPENDER-ROLLINGFILEAPPENDER-INFO" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <!-- 过滤器,只记录 info 级别以上的日志 -->
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <level>INFO</level>
        </filter>
        <!--立即刷新,设置成false可以提高日志吞吐量-->
        <immediateFlush>false</immediateFlush>
        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
            <!-- 日志文件输出的文件名:
                %d:可以包含一个Java.text.SimpleDateFormat指定的时间格式
                %i:自增数字
            -->
            <fileNamePattern>${LOG_PATH}/${MACHINE_IP}/${VIRTUAL_IP}/HISTORY/${LOG_NAME}-info-%d{yyyy-MM-dd}-index%i.log</fileNamePattern>
            <!-- 日志文件保存历史数量:控制保留的归档文件的最大数量,如果超出数量就删除旧文件 -->
            <maxHistory>10</maxHistory>
            <!-- 文件大小超过100MB归档 -->
            <maxFileSize>20MB</maxFileSize>
        </rollingPolicy>
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <pattern>${FILE_LOG_PATTERN}</pattern>
            <charset>${ENCODING}</charset>
        </encoder>
    </appender>

    <!-- 将项目本次运行INFO日志异步输出到文件,按照每天生成日志文件,会自动拼接上一次日志 -->
    <appender name="ASYNC-APPENDER-ROLLINGFILEAPPENDER-INFO" class="ch.qos.logback.classic.AsyncAppender">
        <appender-ref ref="APPENDER-ROLLINGFILEAPPENDER-INFO" />
        <!-- 设置异步阻塞队列的大小,为了不丢失日志建议设置的大一些,单机压测时100000是没问题的,应该不用担心OOM -->
        <queueSize>10000</queueSize>
        <!-- 设置丢弃DEBUG、TRACE、INFO日志的阀值,不丢失 -->
        <discardingThreshold>0</discardingThreshold>
        <!-- 设置队列入队时非阻塞,当队列满时会直接丢弃日志,但是对性能提升极大 -->
        <neverBlock>true</neverBlock>
    </appender>

    <!-- 将项目本次运行DEBUG日志同步输出到文件,按照每天生成日志文件,会自动拼接上一次日志 -->
    <appender name="APPENDER-ROLLINGFILEAPPENDER-DEBUG" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <!-- 过滤器,只记录 info 级别以上的日志 -->
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <level>DEBUG</level>
        </filter>
        <!--立即刷新,设置成false可以提高日志吞吐量-->
        <immediateFlush>false</immediateFlush>
        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
            <!-- 日志文件输出的文件名:
                %d:可以包含一个Java.text.SimpleDateFormat指定的时间格式
                %i:自增数字
            -->
            <fileNamePattern>${LOG_PATH}/${MACHINE_IP}/${VIRTUAL_IP}/HISTORY/${LOG_NAME}-debug-%d{yyyy-MM-dd}-index%i.log</fileNamePattern>
            <!-- 日志文件保存历史数量:控制保留的归档文件的最大数量,如果超出数量就删除旧文件 -->
            <maxHistory>10</maxHistory>
            <!-- 文件大小超过100MB归档 -->
            <maxFileSize>20MB</maxFileSize>
        </rollingPolicy>
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <pattern>${FILE_LOG_PATTERN}</pattern>
            <charset>${ENCODING}</charset>
        </encoder>
    </appender>

    <!-- 将项目本次运行DEBUG日志异步输出到文件,按照每天生成日志文件,会自动拼接上一次日志 -->
    <appender name="ASYNC-APPENDER-ROLLINGFILEAPPENDER-DEBUG" class="ch.qos.logback.classic.AsyncAppender">
        <appender-ref ref="APPENDER-ROLLINGFILEAPPENDER-DEBUG" />
        <!-- 设置异步阻塞队列的大小,为了不丢失日志建议设置的大一些,单机压测时100000是没问题的,应该不用担心OOM -->
        <queueSize>10000</queueSize>
        <!-- 设置丢弃DEBUG、TRACE、INFO日志的阀值,不丢失 -->
        <discardingThreshold>0</discardingThreshold>
        <!-- 设置队列入队时非阻塞,当队列满时会直接丢弃日志,但是对性能提升极大 -->
        <neverBlock>true</neverBlock>
    </appender>

    <!-- 将项目本次运行ERROR日志同步输出到文件,按照每天生成日志文件,会自动拼接上一次日志 -->
    <appender name="APPENDER-ROLLINGFILEAPPENDER-ERROR" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <!-- 过滤器,只记录error级别的日志 -->
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>ERROR</level>
            <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>
        <!--立即刷新,设置成false可以提高日志吞吐量-->
        <immediateFlush>false</immediateFlush>
        <!-- 每天生成一个日志文件,保存30天的日志文件 -->
        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
            <!-- 日志文件输出的文件名:按天回滚 daily -->
            <fileNamePattern>${LOG_PATH}/${MACHINE_IP}/${VIRTUAL_IP}/HISTORY/${LOG_NAME}-error-%d{yyyy-MM-dd}-index%i.log</fileNamePattern>
            <!-- 日志文件保留天数 -->
            <maxHistory>10</maxHistory>
            <!-- 文件大小超过100MB归档 -->
            <maxFileSize>20MB</maxFileSize>
        </rollingPolicy>
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <pattern>${FILE_LOG_PATTERN}</pattern>
            <charset>utf8</charset>
        </encoder>
    </appender>

    <appender name="ASYNC-APPENDER-ROLLINGFILEAPPENDER-ERROR" class="ch.qos.logback.classic.AsyncAppender">
        <appender-ref ref="APPENDER-ROLLINGFILEAPPENDER-ERROR" />
        <!-- 设置异步阻塞队列的大小,为了不丢失日志建议设置的大一些,单机压测时100000是没问题的,应该不用担心OOM -->
        <queueSize>10000</queueSize>
        <!-- 设置丢弃DEBUG、TRACE、INFO日志的阀值,不丢失 -->
        <discardingThreshold>0</discardingThreshold>
        <!-- 设置队列入队时非阻塞,当队列满时会直接丢弃日志,但是对性能提升极大 -->
        <neverBlock>true</neverBlock>
    </appender>
    <!--滚动输出到文件(按照天保存):结束-->

    <!--输出到LOGSTASH:开始-->
    <!-- 将项目本次运行ERROR日志同步输出到文件,按照每天生成日志文件,会自动拼接上一次日志 -->
    <appender name="APPENDER-LOGSTASH" class="net.logstash.logback.appender.LogstashTcpSocketAppender">
        <!--  logstash服务器地址-->
        <destination>${LOGSTASH_HOST}</destination>
        <encoder class="net.logstash.logback.encoder.LoggingEventCompositeJsonEncoder">
            <providers>
                <pattern>
                    <pattern>
                        {
                        "appName":"${INDEX_NAME}",
                        "machineIp":"${MACHINE_IP}",
                        "virtualIp":"${VIRTUAL_IP}",
                        "serviceName":"${LOG_NAME}",
                        "timestamp": "%date{\"yyyy-MM-dd'T'HH:mm:ss,SSSZ\"}",
                        "logLevel":"%level",
                        "message":"%msg%n",
                        "traceId": "%X{X-B3-TraceId:-}",
                        "spanId": "%X{X-B3-SpanId:-}",
                        "spanExport": "%X{X-Span-Export:-}"
                        }
                    </pattern>
                </pattern>
            </providers>
        </encoder>
    </appender>
    <appender name="ASYNC-APPENDER-LOGSTASH" class="ch.qos.logback.classic.AsyncAppender">
        <appender-ref ref="APPENDER-LOGSTASH" />
        <!-- 设置异步阻塞队列的大小,为了不丢失日志建议设置的大一些,单机压测时100000是没问题的,应该不用担心OOM -->
        <queueSize>10000</queueSize>
        <!-- 设置丢弃DEBUG、TRACE、INFO日志的阀值,不丢失 -->
        <discardingThreshold>0</discardingThreshold>
        <!-- 设置队列入队时非阻塞,当队列满时会直接丢弃日志,但是对性能提升极大 -->
        <neverBlock>true</neverBlock>
    </appender>
    <!--输出到logstash:结束-->

    <!--
        开发环境日志级别为DEBUG
        level:用来设置打印级别
        五个常用打印级别从低至高依次为TRACE、DEBUG、INFO、WARN、ERROR
    -->
    <springProfile name="dev">
        <root>
            <!--输出到控制台-->
            <appender-ref ref="STDOUT"/>
            <!--异步非滚动输出到文件-->
            <appender-ref ref="ASYNC-APPENDER-FILEAPPENDER-INFO"/>
            <appender-ref ref="ASYNC-APPENDER-FILEAPPENDER-DEBUG"/>
            <appender-ref ref="ASYNC-APPENDER-FILEAPPENDER-ERROR"/>
            <!--异步滚动输出到文件:dev环境不开启-->
<!--            <appender-ref ref="ASYNC-APPENDER-ROLLINGFILEAPPENDER-INFO"/>-->
<!--            <appender-ref ref="ASYNC-APPENDER-ROLLINGFILEAPPENDER-DEBUG"/>-->
<!--            <appender-ref ref="ASYNC-APPENDER-ROLLINGFILEAPPENDER-ERROR"/>-->
            <!--异步滚动输出到logstash-->
            <appender-ref ref="ASYNC-APPENDER-LOGSTASH"/>
        </root>
    </springProfile>

    <!-- 测试环境日志级别为INFO -->
    <springProfile name="test">
        <root>
            <!--输出到控制台-->
            <appender-ref ref="STDOUT"/>
            <!--异步非滚动输出到文件-->
            <appender-ref ref="ASYNC-APPENDER-FILEAPPENDER-INFO"/>
            <appender-ref ref="ASYNC-APPENDER-FILEAPPENDER-DEBUG"/>
            <appender-ref ref="ASYNC-APPENDER-FILEAPPENDER-ERROR"/>
            <!--异步滚动输出到文件:test环境不开启-->
<!--            <appender-ref ref="ASYNC-APPENDER-ROLLINGFILEAPPENDER-INFO"/>-->
<!--            <appender-ref ref="ASYNC-APPENDER-ROLLINGFILEAPPENDER-DEBUG"/>-->
<!--            <appender-ref ref="ASYNC-APPENDER-ROLLINGFILEAPPENDER-ERROR"/>-->
            <!--异步滚动输出到logstash-->
            <appender-ref ref="ASYNC-APPENDER-LOGSTASH"/>
        </root>
    </springProfile>

    <!-- 生产环境日志级别为INFO -->
    <springProfile name="prod">
        <root>
            <!--输出到控制台-->
            <appender-ref ref="STDOUT"/>
            <!--异步非滚动输出到文件-->
            <appender-ref ref="ASYNC-APPENDER-FILEAPPENDER-INFO"/>
            <appender-ref ref="ASYNC-APPENDER-FILEAPPENDER-DEBUG"/>
            <appender-ref ref="ASYNC-APPENDER-FILEAPPENDER-ERROR"/>
            <!--异步滚动输出到文件-->
            <appender-ref ref="ASYNC-APPENDER-ROLLINGFILEAPPENDER-INFO"/>
            <appender-ref ref="ASYNC-APPENDER-ROLLINGFILEAPPENDER-DEBUG"/>
            <appender-ref ref="ASYNC-APPENDER-ROLLINGFILEAPPENDER-ERROR"/>
            <!--异步滚动输出到logstash-->
            <appender-ref ref="ASYNC-APPENDER-LOGSTASH"/>
        </root>
    </springProfile>

    <!-- rancher环境日志级别为INFO -->
    <springProfile name="rancher">
        <root>
            <!--输出到控制台-->
            <appender-ref ref="STDOUT"/>
            <!--异步非滚动输出到文件-->
            <appender-ref ref="ASYNC-APPENDER-FILEAPPENDER-INFO"/>
            <appender-ref ref="ASYNC-APPENDER-FILEAPPENDER-DEBUG"/>
            <appender-ref ref="ASYNC-APPENDER-FILEAPPENDER-ERROR"/>
            <!--异步滚动输出到文件-->
            <appender-ref ref="ASYNC-APPENDER-ROLLINGFILEAPPENDER-INFO"/>
            <appender-ref ref="ASYNC-APPENDER-ROLLINGFILEAPPENDER-DEBUG"/>
            <appender-ref ref="ASYNC-APPENDER-ROLLINGFILEAPPENDER-ERROR"/>
            <!--异步滚动输出到logstash-->
            <appender-ref ref="ASYNC-APPENDER-LOGSTASH"/>
        </root>
    </springProfile>
</configuration>

test环境配置文件
application.yml
#设置spring项目运行的环境
spring:
  profiles:
    active: '@profile.active@'


application-test.yml
server:
  port: 7005 #访问端口
spring:
  application:
    name: SPRINGCLOUD-BASIC-SAMPLE-REGISTER-CENTER-SINGLE-NODE7005-TEST  #注意:服务名不要出现_
  devtools: #热部署开关
    restart:
      enabled: true
# 将Client作为服务注册到SpringBootAdmin Server端,通过Server来监听项目的运行情况
  boot:
    admin:
      client:
        #因为eureka的配置先加载所以可以使用${eureka.instance.ip-address}这个来动态获取ip,虽然这个键值对配置在下面
        url: http://localhost:${server.port}
eureka:
  instance:
    hostname: localhost
  client:
    register-with-eureka: true #不向注册中心注册自己
    fetch-registry: false #表示自己就是注册中心,我的职责就是维护实例,不需要去检索服务
    service-url:
      defaultZone: http://localhost:7005/eureka
  server:
    enable-self-preservation: true #是否开启自我保护,true:服务失效不直接剔除,false:服务失效直接剔除
    eviction-interval-timer-in-ms: 2000 #默认发送心跳的时间间隔,单位为ms

#配置文件修改说明-------------------------------------------------:开始
#注意:不同的部署环境需要修改的配置
#   1.${logback.path}  #修改日志存放位置,Linxu为/,Windows为\
#       修改原因: Linux和Windows目录结构不同
#配置文件修改说明-------------------------------------------------:结束

#自定义日志配置文件路径
logging:
  config: classpath:logback-custom.xml
  path: D:\repository\workspace\IDEA\PERSONAL\springcloud-eureka\log\ #所有日志存放在位置,加上\方便Linux环境下配置
  level:
    root: info #全局日志输出级别

logback:
  log-name: ${spring.application.name}
  append: false #是否启用append(追加到已经存在日志文件尾部),true:重启项目会追加新日志到之前日志,false:重启项目会清空之前的日志
  immediate-flush: true #是否启用immediateFlush(立即刷新),true:重启项目自动追加,false:重启项目会情况之前的日志
  deploy-machine-ip: localhost #当前微服务所在部署机器ip

#logstash相关配置:开始
logstash:
  host: 192.168.0.4:5044 # logstash地址
  index: '@project.parent.artifactId@' # es中index名称
#logstash相关配置:结束

#actuator监控:开始
#通过下面的配置启用所有的监控端点,默认情况下,这些端点是禁用的;
management:
  endpoints:
    web:
      exposure:
        include: '*'
    enabled-by-default: true
  endpoint:
    health:
      show-details: always # 访问/actuator/health时,显示详细信息,而不是仅仅显示"status": "UP"
    # 日志文件路径:特别注意,此处无法配置日志文件路径,因为rancher会生成虚拟ip,这个虚拟ip是无法在这里获取的,
    #           但是虚拟ip是路径的一部分,所以这个路径无法拼接出来,所以这里无法配置日志文件路径
    #logfile:
    #  external-file:
#actuator监控:结束

logback-custom.xml
<?xml version="1.0" encoding="UTF-8"?>

<!--
    scan: 当此属性设置为true时,配置文件如果发生改变,将会被重新加载,默认值为true。
    scanPeriod: 设置监测配置文件是否有修改的时间间隔,如果没有给出时间单位,默认单位是毫秒。当scan为true时,此属性生效。默认的时间间隔为1分钟。
    debug: 当此属性设置为true时,将打印出logback内部日志信息,实时查看logback运行状态。默认值为false。
-->
<!-- 输出logback内部日志信息,每隔30s判断一下配置文件有没有更新,若更新,则重新加载 -->
<configuration scan="true" scanPeriod="30 seconds" debug="false">
    <!--从java代码中获取虚拟ip的值-->
    <!--获取当前微服务部署虚拟IP,如rancher为当前微服务分配的ip-->
    <define name="VIRTUAL_IP" class="org.openatom.springcloud.config.VirtualIpConfig"/>

    <!--从Spring容器中获取配置(Spring配置文件加载顺序:bootstrap.yml->logback.xml->application.yml)-->
    <!--获取当前微服务部署机器ip-->
    <springProperty name="MACHINE_IP" scope="context" source="logback.deploy-machine-ip"/>
    <!--应用名称-->
    <springProperty name="LOG_NAME" scope="context" source="logback.log-name"/>
    <!--是否启用append-->
    <springProperty name="IS_APPEND" scope="context" source="logback.append"/>
    <!--是否启用立即刷新-->
    <springProperty name="IS_IMMEDIATEFLUSH" scope="context" source="logback.immediate-flush"/>
    <springProperty name="LOG_PATH" scope="context" source="logging.path"/>
    <!--logstash地址-->
    <springProperty name="LOGSTASH_HOST" scope="context" source="logstash.host"/>
    <!--索引名称-->
    <springProperty name="INDEX_NAME" scope="context" source="logstash.index"/>


    <!-- name:变量的名称,可以随意起名,但建议名字要简明直译;value:变量的值;在配置文件中,我们可以用 ${} 的方式来使用,将变量引入到其他节点中去。-->
    <!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度 %msg:日志消息,%n是换行符-->
    <!--控制台日志输出预选样式-->
    <property name="CONSOLE_LOG_PATTERN_1" value="%red(%d{yyyy-MM-dd HH:mm:ss.SSS}) %green([%thread]) [machineIp:${MACHINE_IP} virtualIp:${VIRTUAL_IP}] [TraceId:%X{X-B3-TraceId:-} SpanId:%X{X-B3-SpanId:-} %highlight(%-5level) %boldMagenta(%logger{10}): %cyan(%msg%n)"/>
    <property name="CONSOLE_LOG_PATTERN_2" value="%yellow(%date{yyyy-MM-dd HH:mm:ss}) [machineIp:${MACHINE_IP} virtualIp:${VIRTUAL_IP}] [TraceId:%X{X-B3-TraceId:-} SpanId:%X{X-B3-SpanId:-} %highlight([%-5level]) %green(%logger) %msg%n"/>
    <property name="CONSOLE_LOG_PATTERN_3" value="%date{yyyy-MM-dd HH:mm:ss} [machineIp:${MACHINE_IP} virtualIp:${VIRTUAL_IP}] [TraceId:%X{X-B3-TraceId:-} SpanId:%X{X-B3-SpanId:-} Span-Export:%X{X-Span-Export:-}]  %green(%-5level) %boldMagenta(${PID:-}) -- [%+20thread] %cyan(%logger{20}) %line       : %msg%n"/>
    <!--文件中日志输出预选样式-->
    <property name="FILE_LOG_PATTERN_1" value="%d{yyyyMMdd:HH:mm:ss.SSS} [machineIp:${MACHINE_IP} virtualIp:${VIRTUAL_IP}] [TraceId:%X{X-B3-TraceId:-} SpanId:%X{X-B3-SpanId:-} [%thread] %-5level  %msg%n"/>

    <!--控制台日志输出格式-->
    <property name="CONSOLE_LOG_PATTERN" value="${CONSOLE_LOG_PATTERN_3}"/>
    <!--文件中日志输出格式-->
    <property name="FILE_LOG_PATTERN" value="${FILE_LOG_PATTERN_1}"/>
    <!--日志名称-->
    <!--定义默认日志输出级别-->
    <property name="LOG_OUTPUT_LEVEL" value="${LOG_LEVEL}" />
    <!--定义默认日志输出编码-->
    <property name="ENCODING" value="UTF-8" />

    <!-- 控制台输出:开始 -->
    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
        <!-- 用来设置日志的输入格式,使用“%+转换符”的方式,如果要输出”%”则必须使用”\”进行转义。-->
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <!-- 格式化输出:https://logback.qos.ch/manual/layouts.html
                 %d 表示日期,
                 %thread 表示线程名,
                 %level 日志级别从左显示5个字符宽度,
                 %t 线程名
                 %file:%line 文件名+行号,
                 %m 日志消息,%n是换行符
                 %X{traceId}:自定义设置的参数,后面会说。
            -->
            <pattern>${CONSOLE_LOG_PATTERN}</pattern>
            <charset>${ENCODING}</charset>
        </encoder>
    </appender>
    <!-- 控制台输出:结束 -->

    <!--输出到文件:开始-->
    <!-- 将项目本次运行INFO日志同步输出到文件,会自动清空文件中上一次的日志 -->
    <appender name="APPENDER-FILEAPPENDER-INFO" class="ch.qos.logback.core.FileAppender">
        <!-- 过滤器,只记录 info 级别以上的日志 -->
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <level>INFO</level>
        </filter>
        <!-- 写入的日志文件名,可以使相对目录也可以是绝对目录,如果上级目录不存在则自动创建 -->
        <file>${LOG_PATH}/${MACHINE_IP}/${VIRTUAL_IP}/${LOG_NAME}-info.log</file>
        <!-- 如果为true表示日志被追加到文件结尾,如果是false表示清空文件 -->
        <append>${IS_APPEND}</append>
        <!--立即刷新,设置成false可以提高日志吞吐量-->
        <immediateFlush>${IS_IMMEDIATEFLUSH}</immediateFlush>
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <pattern>${FILE_LOG_PATTERN}</pattern>
            <charset>${ENCODING}</charset>
        </encoder>
    </appender>

    <!-- 将项目本次运行INFO日志异步输出到文件,会自动清空文件中上一次的日志 -->
    <appender name="ASYNC-APPENDER-FILEAPPENDER-INFO" class="ch.qos.logback.classic.AsyncAppender">
        <appender-ref ref="APPENDER-FILEAPPENDER-INFO" />
        <!-- 设置异步阻塞队列的大小,为了不丢失日志建议设置的大一些,单机压测时100000是没问题的,应该不用担心OOM -->
        <queueSize>10000</queueSize>
        <!-- 设置丢弃DEBUG、TRACE、INFO日志的阀值,不丢失 -->
        <discardingThreshold>0</discardingThreshold>
        <!-- 设置队列入队时非阻塞,当队列满时会直接丢弃日志,但是对性能提升极大 -->
        <neverBlock>${IS_IMMEDIATEFLUSH}</neverBlock>
    </appender>

    <!-- 将项目本次运行DEBUG日志同步输出到文件,会自动清空文件中上一次的日志 -->
    <appender name="APPENDER-FILEAPPENDER-DEBUG" class="ch.qos.logback.core.FileAppender">
        <!-- 过滤器,只记录 info 级别以上的日志 -->
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <level>DEBUG</level>
        </filter>
        <!-- 写入的日志文件名,可以使相对目录也可以是绝对目录,如果上级目录不存在则自动创建 -->
        <file>${LOG_PATH}/${MACHINE_IP}/${VIRTUAL_IP}/${LOG_NAME}-debug.log</file>
        <!-- 如果为true表示日志被追加到文件结尾,如果是false表示清空文件 -->
        <append>${IS_APPEND}</append>
        <!--立即刷新,设置成false可以提高日志吞吐量-->
        <immediateFlush>true</immediateFlush>
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <pattern>${FILE_LOG_PATTERN}</pattern>
            <charset>${ENCODING}</charset>
        </encoder>
    </appender>

    <!-- 将项目本次运行DEBUG日志异步输出到文件,会自动清空文件中上一次的日志 -->
    <appender name="ASYNC-APPENDER-FILEAPPENDER-DEBUG" class="ch.qos.logback.classic.AsyncAppender">
        <appender-ref ref="APPENDER-FILEAPPENDER-DEBUG" />
        <!-- 设置异步阻塞队列的大小,为了不丢失日志建议设置的大一些,单机压测时100000是没问题的,应该不用担心OOM -->
        <queueSize>10000</queueSize>
        <!-- 设置丢弃DEBUG、TRACE、INFO日志的阀值,不丢失 -->
        <discardingThreshold>0</discardingThreshold>
        <!-- 设置队列入队时非阻塞,当队列满时会直接丢弃日志,但是对性能提升极大 -->
        <neverBlock>true</neverBlock>
    </appender>

    <!-- 将项目本次运行ERROR日志同步输出到文件,会自动清空文件中上一次的日志 -->
    <appender name="APPENDER-FILEAPPENDER-ERROR" class="ch.qos.logback.core.FileAppender">
        <!-- 过滤器,只记录 info 级别以上的日志 -->
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <level>DEBUG</level>
        </filter>
        <!-- 写入的日志文件名,可以使相对目录也可以是绝对目录,如果上级目录不存在则自动创建 -->
        <file>${LOG_PATH}/${MACHINE_IP}/${VIRTUAL_IP}/${LOG_NAME}-error.log</file>
        <!-- 如果为true表示日志被追加到文件结尾,如果是false表示清空文件 -->
        <append>${IS_APPEND}</append>
        <!--立即刷新,设置成false可以提高日志吞吐量-->
        <immediateFlush>${IS_IMMEDIATEFLUSH}</immediateFlush>
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <pattern>${FILE_LOG_PATTERN}</pattern>
            <charset>${ENCODING}</charset>
        </encoder>
    </appender>

    <!-- 将项目本次运行ERROR日志异步输出到文件,会自动清空文件中上一次的日志 -->
    <appender name="ASYNC-APPENDER-FILEAPPENDER-ERROR" class="ch.qos.logback.classic.AsyncAppender">
        <appender-ref ref="APPENDER-FILEAPPENDER-ERROR" />
        <!-- 设置异步阻塞队列的大小,为了不丢失日志建议设置的大一些,单机压测时100000是没问题的,应该不用担心OOM -->
        <queueSize>10000</queueSize>
        <!-- 设置丢弃DEBUG、TRACE、INFO日志的阀值,不丢失 -->
        <discardingThreshold>0</discardingThreshold>
        <!-- 设置队列入队时非阻塞,当队列满时会直接丢弃日志,但是对性能提升极大 -->
        <neverBlock>true</neverBlock>
    </appender>
    <!--输出到文件:结束-->


    <!--滚动输出到文件(按照天保存):开始-->
    <!-- 将项目本次运行INFO日志同步输出到文件,按照每天生成日志文件,会自动拼接上一次日志 -->
    <appender name="APPENDER-ROLLINGFILEAPPENDER-INFO" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <!-- 过滤器,只记录 info 级别以上的日志 -->
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <level>INFO</level>
        </filter>
        <!--立即刷新,设置成false可以提高日志吞吐量-->
        <immediateFlush>false</immediateFlush>
        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
            <!-- 日志文件输出的文件名:
                %d:可以包含一个Java.text.SimpleDateFormat指定的时间格式
                %i:自增数字
            -->
            <fileNamePattern>${LOG_PATH}/${MACHINE_IP}/${VIRTUAL_IP}/HISTORY/${LOG_NAME}-info-%d{yyyy-MM-dd}-index%i.log</fileNamePattern>
            <!-- 日志文件保存历史数量:控制保留的归档文件的最大数量,如果超出数量就删除旧文件 -->
            <maxHistory>10</maxHistory>
            <!-- 文件大小超过100MB归档 -->
            <maxFileSize>20MB</maxFileSize>
        </rollingPolicy>
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <pattern>${FILE_LOG_PATTERN}</pattern>
            <charset>${ENCODING}</charset>
        </encoder>
    </appender>

    <!-- 将项目本次运行INFO日志异步输出到文件,按照每天生成日志文件,会自动拼接上一次日志 -->
    <appender name="ASYNC-APPENDER-ROLLINGFILEAPPENDER-INFO" class="ch.qos.logback.classic.AsyncAppender">
        <appender-ref ref="APPENDER-ROLLINGFILEAPPENDER-INFO" />
        <!-- 设置异步阻塞队列的大小,为了不丢失日志建议设置的大一些,单机压测时100000是没问题的,应该不用担心OOM -->
        <queueSize>10000</queueSize>
        <!-- 设置丢弃DEBUG、TRACE、INFO日志的阀值,不丢失 -->
        <discardingThreshold>0</discardingThreshold>
        <!-- 设置队列入队时非阻塞,当队列满时会直接丢弃日志,但是对性能提升极大 -->
        <neverBlock>true</neverBlock>
    </appender>

    <!-- 将项目本次运行DEBUG日志同步输出到文件,按照每天生成日志文件,会自动拼接上一次日志 -->
    <appender name="APPENDER-ROLLINGFILEAPPENDER-DEBUG" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <!-- 过滤器,只记录 info 级别以上的日志 -->
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <level>DEBUG</level>
        </filter>
        <!--立即刷新,设置成false可以提高日志吞吐量-->
        <immediateFlush>false</immediateFlush>
        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
            <!-- 日志文件输出的文件名:
                %d:可以包含一个Java.text.SimpleDateFormat指定的时间格式
                %i:自增数字
            -->
            <fileNamePattern>${LOG_PATH}/${MACHINE_IP}/${VIRTUAL_IP}/HISTORY/${LOG_NAME}-debug-%d{yyyy-MM-dd}-index%i.log</fileNamePattern>
            <!-- 日志文件保存历史数量:控制保留的归档文件的最大数量,如果超出数量就删除旧文件 -->
            <maxHistory>10</maxHistory>
            <!-- 文件大小超过100MB归档 -->
            <maxFileSize>20MB</maxFileSize>
        </rollingPolicy>
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <pattern>${FILE_LOG_PATTERN}</pattern>
            <charset>${ENCODING}</charset>
        </encoder>
    </appender>

    <!-- 将项目本次运行DEBUG日志异步输出到文件,按照每天生成日志文件,会自动拼接上一次日志 -->
    <appender name="ASYNC-APPENDER-ROLLINGFILEAPPENDER-DEBUG" class="ch.qos.logback.classic.AsyncAppender">
        <appender-ref ref="APPENDER-ROLLINGFILEAPPENDER-DEBUG" />
        <!-- 设置异步阻塞队列的大小,为了不丢失日志建议设置的大一些,单机压测时100000是没问题的,应该不用担心OOM -->
        <queueSize>10000</queueSize>
        <!-- 设置丢弃DEBUG、TRACE、INFO日志的阀值,不丢失 -->
        <discardingThreshold>0</discardingThreshold>
        <!-- 设置队列入队时非阻塞,当队列满时会直接丢弃日志,但是对性能提升极大 -->
        <neverBlock>true</neverBlock>
    </appender>

    <!-- 将项目本次运行ERROR日志同步输出到文件,按照每天生成日志文件,会自动拼接上一次日志 -->
    <appender name="APPENDER-ROLLINGFILEAPPENDER-ERROR" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <!-- 过滤器,只记录error级别的日志 -->
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>ERROR</level>
            <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>
        <!--立即刷新,设置成false可以提高日志吞吐量-->
        <immediateFlush>false</immediateFlush>
        <!-- 每天生成一个日志文件,保存30天的日志文件 -->
        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
            <!-- 日志文件输出的文件名:按天回滚 daily -->
            <fileNamePattern>${LOG_PATH}/${MACHINE_IP}/${VIRTUAL_IP}/HISTORY/${LOG_NAME}-error-%d{yyyy-MM-dd}-index%i.log</fileNamePattern>
            <!-- 日志文件保留天数 -->
            <maxHistory>10</maxHistory>
            <!-- 文件大小超过100MB归档 -->
            <maxFileSize>20MB</maxFileSize>
        </rollingPolicy>
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <pattern>${FILE_LOG_PATTERN}</pattern>
            <charset>utf8</charset>
        </encoder>
    </appender>

    <appender name="ASYNC-APPENDER-ROLLINGFILEAPPENDER-ERROR" class="ch.qos.logback.classic.AsyncAppender">
        <appender-ref ref="APPENDER-ROLLINGFILEAPPENDER-ERROR" />
        <!-- 设置异步阻塞队列的大小,为了不丢失日志建议设置的大一些,单机压测时100000是没问题的,应该不用担心OOM -->
        <queueSize>10000</queueSize>
        <!-- 设置丢弃DEBUG、TRACE、INFO日志的阀值,不丢失 -->
        <discardingThreshold>0</discardingThreshold>
        <!-- 设置队列入队时非阻塞,当队列满时会直接丢弃日志,但是对性能提升极大 -->
        <neverBlock>true</neverBlock>
    </appender>
    <!--滚动输出到文件(按照天保存):结束-->

    <!--输出到LOGSTASH:开始-->
    <!-- 将项目本次运行ERROR日志同步输出到文件,按照每天生成日志文件,会自动拼接上一次日志 -->
    <appender name="APPENDER-LOGSTASH" class="net.logstash.logback.appender.LogstashTcpSocketAppender">
        <!--  logstash服务器地址-->
        <destination>${LOGSTASH_HOST}</destination>
        <encoder class="net.logstash.logback.encoder.LoggingEventCompositeJsonEncoder">
            <providers>
                <pattern>
                    <pattern>
                        {
                        "appName":"${INDEX_NAME}",
                        "machineIp":"${MACHINE_IP}",
                        "virtualIp":"${VIRTUAL_IP}",
                        "serviceName":"${LOG_NAME}",
                        "timestamp": "%date{\"yyyy-MM-dd'T'HH:mm:ss,SSSZ\"}",
                        "logLevel":"%level",
                        "message":"%msg%n",
                        "traceId": "%X{X-B3-TraceId:-}",
                        "spanId": "%X{X-B3-SpanId:-}",
                        "spanExport": "%X{X-Span-Export:-}"
                        }
                    </pattern>
                </pattern>
            </providers>
        </encoder>
    </appender>
    <appender name="ASYNC-APPENDER-LOGSTASH" class="ch.qos.logback.classic.AsyncAppender">
        <appender-ref ref="APPENDER-LOGSTASH" />
        <!-- 设置异步阻塞队列的大小,为了不丢失日志建议设置的大一些,单机压测时100000是没问题的,应该不用担心OOM -->
        <queueSize>10000</queueSize>
        <!-- 设置丢弃DEBUG、TRACE、INFO日志的阀值,不丢失 -->
        <discardingThreshold>0</discardingThreshold>
        <!-- 设置队列入队时非阻塞,当队列满时会直接丢弃日志,但是对性能提升极大 -->
        <neverBlock>true</neverBlock>
    </appender>
    <!--输出到logstash:结束-->

    <!--
        开发环境日志级别为DEBUG
        level:用来设置打印级别
        五个常用打印级别从低至高依次为TRACE、DEBUG、INFO、WARN、ERROR
    -->
    <springProfile name="dev">
        <root>
            <!--输出到控制台-->
            <appender-ref ref="STDOUT"/>
            <!--异步非滚动输出到文件-->
            <appender-ref ref="ASYNC-APPENDER-FILEAPPENDER-INFO"/>
            <appender-ref ref="ASYNC-APPENDER-FILEAPPENDER-DEBUG"/>
            <appender-ref ref="ASYNC-APPENDER-FILEAPPENDER-ERROR"/>
            <!--异步滚动输出到文件:dev环境不开启-->
<!--            <appender-ref ref="ASYNC-APPENDER-ROLLINGFILEAPPENDER-INFO"/>-->
<!--            <appender-ref ref="ASYNC-APPENDER-ROLLINGFILEAPPENDER-DEBUG"/>-->
<!--            <appender-ref ref="ASYNC-APPENDER-ROLLINGFILEAPPENDER-ERROR"/>-->
            <!--异步滚动输出到logstash-->
            <appender-ref ref="ASYNC-APPENDER-LOGSTASH"/>
        </root>
    </springProfile>

    <!-- 测试环境日志级别为INFO -->
    <springProfile name="test">
        <root>
            <!--输出到控制台-->
            <appender-ref ref="STDOUT"/>
            <!--异步非滚动输出到文件-->
            <appender-ref ref="ASYNC-APPENDER-FILEAPPENDER-INFO"/>
            <appender-ref ref="ASYNC-APPENDER-FILEAPPENDER-DEBUG"/>
            <appender-ref ref="ASYNC-APPENDER-FILEAPPENDER-ERROR"/>
            <!--异步滚动输出到文件:test环境不开启-->
<!--            <appender-ref ref="ASYNC-APPENDER-ROLLINGFILEAPPENDER-INFO"/>-->
<!--            <appender-ref ref="ASYNC-APPENDER-ROLLINGFILEAPPENDER-DEBUG"/>-->
<!--            <appender-ref ref="ASYNC-APPENDER-ROLLINGFILEAPPENDER-ERROR"/>-->
            <!--异步滚动输出到logstash-->
            <appender-ref ref="ASYNC-APPENDER-LOGSTASH"/>
        </root>
    </springProfile>

    <!-- 生产环境日志级别为INFO -->
    <springProfile name="prod">
        <root>
            <!--输出到控制台-->
            <appender-ref ref="STDOUT"/>
            <!--异步非滚动输出到文件-->
            <appender-ref ref="ASYNC-APPENDER-FILEAPPENDER-INFO"/>
            <appender-ref ref="ASYNC-APPENDER-FILEAPPENDER-DEBUG"/>
            <appender-ref ref="ASYNC-APPENDER-FILEAPPENDER-ERROR"/>
            <!--异步滚动输出到文件-->
            <appender-ref ref="ASYNC-APPENDER-ROLLINGFILEAPPENDER-INFO"/>
            <appender-ref ref="ASYNC-APPENDER-ROLLINGFILEAPPENDER-DEBUG"/>
            <appender-ref ref="ASYNC-APPENDER-ROLLINGFILEAPPENDER-ERROR"/>
            <!--异步滚动输出到logstash-->
            <appender-ref ref="ASYNC-APPENDER-LOGSTASH"/>
        </root>
    </springProfile>

    <!-- rancher环境日志级别为INFO -->
    <springProfile name="rancher">
        <root>
            <!--输出到控制台-->
            <appender-ref ref="STDOUT"/>
            <!--异步非滚动输出到文件-->
            <appender-ref ref="ASYNC-APPENDER-FILEAPPENDER-INFO"/>
            <appender-ref ref="ASYNC-APPENDER-FILEAPPENDER-DEBUG"/>
            <appender-ref ref="ASYNC-APPENDER-FILEAPPENDER-ERROR"/>
            <!--异步滚动输出到文件-->
            <appender-ref ref="ASYNC-APPENDER-ROLLINGFILEAPPENDER-INFO"/>
            <appender-ref ref="ASYNC-APPENDER-ROLLINGFILEAPPENDER-DEBUG"/>
            <appender-ref ref="ASYNC-APPENDER-ROLLINGFILEAPPENDER-ERROR"/>
            <!--异步滚动输出到logstash-->
            <appender-ref ref="ASYNC-APPENDER-LOGSTASH"/>
        </root>
    </springProfile>
</configuration>

20.5.7.编写模块config

package org.openatom.springcloud.config;

import ch.qos.logback.core.PropertyDefinerBase;
import lombok.extern.slf4j.Slf4j;

import java.net.InetAddress;
import java.net.UnknownHostException;

@Slf4j
public class VirtualIpConfig extends PropertyDefinerBase {
    private static String virtualIp;
    static {
        try {
            virtualIp = InetAddress.getLocalHost().getHostAddress();
        } catch (UnknownHostException e) {
            log.error("获取日志Ip异常", e);
            virtualIp = null;
        }
    }

    @Override
    public String getPropertyValue() {
        return virtualIp;
    }
}

20.5.8.编写模块主启动类

package org.openatom.springcloud;

import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;

@SpringBootApplication
@EnableEurekaServer
@Slf4j
public class BasicSampleRegisterCcenterSingleNode7005 {
    public static void main(String[] args) {
        SpringApplication.run(BasicSampleRegisterCcenterSingleNode7005.class,args);
    }
}

20.5.9.测试模块

在浏览器中访问
http://localhost:7005/
看到如下界面代表搭建成功

20.6.搭建服务提供者第一个节点

20.6.1.模块简介

为综合案例搭建服务提供者的第一个节点,启动端口: 8009

20.6.2.模块目录结构

springcloud-basic-sample-provider-cluster-node-payment8009
|-- docker
|   •-- Dockerfile
|-- src
|   •-- main
|       |-- java
|       |   •-- org
|       |       •-- openatom
|       |           •-- springcloud
|       |               |-- config
|       |               |   •-- VirtualIpConfig.java
|       |               |-- controller
|       |               |   •-- PaymentController.java
|       |               |-- dao
|       |               |   •-- PaymentDao.java
|       |               |-- service
|       |               |   |-- impl
|       |               |   |   •-- PaymentServiceImpl.java
|       |               |   •-- PaymentService.java
|       |               •-- BasicSamplePaymentServiceProviderClusterNode8009.java
|       •-- resources
|           |-- dev
|           |   |-- mapper
|           |   |   •-- PaymentMapper.xml
|           |   |-- application-dev.yml
|           |   |-- application.yml
|           |   •-- logback-custom.xml
|           |-- prod
|           |   |-- mapper
|           |   |   •-- PaymentMapper.xml
|           |   |-- application-prod.yml
|           |   |-- application.yml
|           |   •-- logback-custom.xml
|           |-- rancher
|           |   |-- mapper
|           |   |   •-- PaymentMapper.xml
|           |   |-- application-rancher.yml
|           |   |-- application.yml
|           |   •-- logback-custom.xml
|           •-- test
|               |-- mapper
|               |   •-- PaymentMapper.xml
|               |-- application-test.yml
|               |-- application.yml
|               •-- logback-custom.xml
•-- pom.xml

20.6.3.创建模块

在父工程(springcloud-eureka)中创建一个名为springcloud-basic-sample-provider-cluster-node-payment8009的maven模块,注意:当前模块创建成功后,在父工程pom.xml中<modules></modules>中会自动生成有关当前模块的信息

20.6.4.编写模块pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>springcloud-eureka</artifactId>
        <groupId>org.openatom</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>springcloud-basic-sample-provider-cluster-node-payment8009</artifactId>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
        <!--设置当前服务端口-->
        <docker.container.port>8009</docker.container.port>
        <!--docker容器端口映射-->
        <docker.port.mapping>${docker.container.port}:${docker.container.port}</docker.port.mapping>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid-spring-boot-starter</artifactId>
        </dependency>
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jdbc</artifactId>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
        <!--引入公共的工程-->
        <dependency>
            <groupId>org.openatom</groupId>
            <artifactId>springcloud-api-commons</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
        <dependency>
            <groupId>de.codecentric</groupId>
            <artifactId>spring-boot-admin-starter-client</artifactId>
        </dependency>
        <dependency>
            <groupId>net.logstash.logback</groupId>
            <artifactId>logstash-logback-encoder</artifactId>
        </dependency>
        <!--包含了sleuth+zipkin-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-zipkin</artifactId>
        </dependency>
    </dependencies>

    <!--热部署需要加这个-->
    <build>
        <finalName>${project.artifactId}</finalName>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <executions>
                    <execution>
                        <!--把当前插件repackage命令和maven的package绑定-->
                        <id>repackage-original</id>
                        <phase>package</phase>
                        <goals>
                            <goal>repackage</goal>
                        </goals>
                    </execution>
                </executions>
                <configuration>
                    <fork>true</fork>
                    <addResources>true</addResources>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-resources-plugin</artifactId>
                <configuration>
                    <encoding>UTF-8</encoding>
                    <delimiters>
                        <delimiter>@</delimiter>
                    </delimiters>
                    <useDefaultDelimiters>false</useDefaultDelimiters>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-antrun-plugin</artifactId>
                <executions>
                    <execution>
                        <id>del-jar</id>
                        <phase>clean</phase>
                        <configuration>
                            <tasks>
                                <!-- 这是将当前模块下的target下的jar包删除-->
                                <delete file="docker/${build.finalName}.jar"/>
                            </tasks>
                        </configuration>
                        <goals>
                            <goal>run</goal>
                        </goals>
                    </execution>
                    <execution>
                        <id>copy-jar</id>
                        <phase>install</phase>
                        <configuration>
                            <tasks>
                                <!-- 这是将当前模块下的target下的jar包copy到当前模块根目录下docker目录中-->
                                <copy todir="docker" file="target/${build.finalName}.jar"></copy>
                            </tasks>
                        </configuration>
                        <goals>
                            <goal>run</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
            <plugin>
                <groupId>io.fabric8</groupId>
                <artifactId>docker-maven-plugin</artifactId>
                <configuration>
                    <dockerHost>${docker.host}</dockerHost>
                    <removeMode>true</removeMode>
                    <!--
                        harbor镜像仓库认证配置
                        注意:不管是harbor中是公开项目还是私密项目,这个配置都要加,不加无法push成功
                    -->
                    <authConfig>
                        <username>${docker.registry.username}</username>
                        <password>${docker.registry.password}</password>
                    </authConfig>
                    <images>
                        <image>
                            <!--显示日志的时候-->
                            <!--<alias>spring-cloud-eureka</alias>-->
                            <!--如果只给docker本地镜像库中推送,格式为 命名空间/项目名称:tags名称,示例:项目artifactId/模块artifactId-->
                            <!--<name>${project.parent.artifactId}/${project.name}</name>-->
                            <!--
                                如果要同时给私服中推送,格式为 registry的ip:命名空间/项目名称:tags名称,示例:私服的ip:项目artifactId/模块artifactId
                                也可将registry单独写在下面
                            -->
                            <!--<name>镜像名称:${docker.registry}/${project.parent.artifactId}/${project.name}</name>-->
                            <name>${project.parent.artifactId}/${project.name}:latest</name>
                            <registry>${docker.registry.uri}</registry>
                            <!--定义镜像构建行为-->
                            <build>
                                <!-- 指定dockerfile文件的位置-->
                                <dockerFile>${project.basedir}/docker/Dockerfile</dockerFile>
                            </build>
                            <!-- 定义容器启动行为-->
                            <run>
                                <!--设置容器名,可采用通配符-->
                                <containerNamePattern>${project.parent.artifactId}_${project.build.finalName}</containerNamePattern>
                                <!--设置端口映射-->
                                <ports>
                                    <port>${docker.port.mapping}</port>
                                </ports>
                                <links>
                                    <link>mysql</link>
                                </links>
                            </run>
                        </image>
                    </images>
                    <buildArgs>
                        <!--docker私服地址-->
                        <DOCKER_REGISTRY_URL>${docker.registry.uri}</DOCKER_REGISTRY_URL>
                    </buildArgs>
                </configuration>
                <executions>
                    <!--如果想在项目install时构建镜像添加-->
                    <execution>
                        <id>build-image</id>
                        <phase>install</phase>
                        <goals>
                            <goal>build</goal>
                        </goals>
                    </execution>
                    <!--如果想在项目install时构建镜像添加-->
                    <execution>
                        <id>tag-image</id>
                        <phase>install</phase>
                        <goals>
                            <goal>tag</goal>
                        </goals>
                    </execution>
                    <!--如果想在项目install时推送镜像到私服添加-->
                    <execution>
                        <id>push-image</id>
                        <phase>install</phase>
                        <goals>
                            <goal>push</goal>
                        </goals>
                    </execution>
                    <!--如果想在项目install时推送镜像到私服后删除并docker中本地build的镜像添加-->
                    <execution>
                        <id>remove-image</id>
                        <phase>install</phase>
                        <goals>
                            <goal>remove</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
        <!--打包多环境-->
        <resources>
            <resource>
                <directory>src/main/resources</directory>
                <excludes>
                    <exclude>**/*.yml</exclude>
                    <exclude>**/*.xml</exclude>
                </excludes>
            </resource>
            <resource>
                <directory>src/main/resources/${profile.active}</directory>
                <!--引入所需环境的配置文件-->
                <filtering>true</filtering>
                <includes>
                    <include>application.yml</include>
                    <!--根据maven选择环境导入配置文件-->
                    <include>application-${profile.active}.yml</include>
                    <include>mapper/*.xml</include>
                    <include>*.xml</include>
                </includes>
            </resource>
        </resources>
    </build>
</project>

/pom.xml"

20.6.5.编写模块配置文件

dev环境配置文件
application.yml
#设置spring项目运行的环境
spring:
  profiles:
    active: '@profile.active@'


application-dev.yml
server:
  port: 8009 #访问端口
spring:
  application:
    name: SPRINGCLOUD-BASIC-SAMPLE-PROVIDER-PAYMENT-SERVICE-CLUSTER-DEV  #注意:服务名不要出现_
  devtools: #热部署开关
    restart:
      enabled: true
  # 将Client作为服务注册到SpringBootAdmin Server端,通过Server来监听项目的运行情况
  boot:
    admin:
      client:
        url: http://localhost:${server.port}
  zipkin:
    base-url: http://localhost:9411
  sleuth:
    sampler:
      probability: 1  # span的采样率,默认为 0.1,这个值介于0到1之间
  logging:
    level: info
  datasource:
    type: com.alibaba.druid.pool.DruidDataSource            # 当前数据源操作类型
    driver-class-name: com.mysql.cj.jdbc.Driver              # mysql驱动包
    url: jdbc:mysql://192.168.0.5:3306/payment?useUnicode=true&characterEncoding=utf-8&useSSL=false
    username: root
    password: Mysql123456_

eureka:
  client:
    register-with-eureka: true  #表示是否将自己注册进EurekaServer默认为true。
    fetchRegistry: true  #是否从EurekaServer抓取已有的注册信息,默认为true。单节点无所谓,集群必须设置为true才能配合ribbon使用负载均衡
    service-url:
      #单机版
      defaultZone: http://localhost:7005/eureka
      #集群版
      #defaultZone: http://eureka7002:7002/eureka,http://eureka7003:7003/eureka,http://eureka7004:7004/eureka
  instance:
    instance-id: SPRINGCLOUD-PROVIDER-PAYMENT-SERVICE-CLUSTER-NODE-PAYMENT8009-DEV #Eureka仪表盘中Instances currently registered with Eureka.Status显示的内容
    #当前微服务所在部署机器ip
    ip-address: localhost
    prefer-ip-address: true  #访问路径可以显示IP地址,点击Eureka仪表盘中Instances currently registered with Eureka.Status显示的内容地址栏是否显示IP地址
    lease-renewal-interval-in-seconds: 30 #Eureka客户端向服务端发送心跳的时间间隔,单位为秒(默认是30秒)
    lease-expiration-duration-in-seconds: 90 #Eureka服务端在收到最后一次心跳后等待时间上限,单位为秒(默认是90秒),超时将剔除服务

mybatis:
  mapperLocations: classpath:mapper/*.xml
  type-aliases-package: org.openatom.springcloud.entities    # 所有Entity别名类所在包


#配置文件修改说明-------------------------------------------------:开始
#注意:不同的部署环境需要修改的配置
#   1.${logback.path}  #修改日志存放位置,Linxu为/,Windows为\
#       修改原因: Linux和Windows目录结构不同
#配置文件修改说明-------------------------------------------------:结束

#自定义日志配置文件路径
logging:
  config: classpath:logback-custom.xml
  path: D:\repository\workspace\IDEA\PERSONAL\springcloud-eureka\log\ #所有日志存放在位置,加上\方便Linux环境下配置
  level:
    root: info #全局日志输出级别

logback:
  log-name: ${spring.application.name}
  append: false #是否启用append(追加到已经存在日志文件尾部),true:重启项目会追加新日志到之前日志,false:重启项目会清空之前的日志
  immediate-flush: true #是否启用immediateFlush(立即刷新),true:重启项目自动追加,false:重启项目会情况之前的日志
  deploy-machine-ip: ${eureka.instance.ip-address} #当前微服务所在部署机器ip

#logstash相关配置:开始
logstash:
  host: 192.168.0.4:5044 # logstash地址
  index: '@project.parent.artifactId@' # es中index名称
#logstash相关配置:结束

#actuator监控:开始
#通过下面的配置启用所有的监控端点,默认情况下,这些端点是禁用的;
management:
  endpoints:
    web:
      exposure:
        include: '*'
    enabled-by-default: true
  endpoint:
    health:
      show-details: always # 访问/actuator/health时,显示详细信息,而不是仅仅显示"status": "UP"
    # 日志文件路径:特别注意,此处无法配置日志文件路径,因为rancher会生成虚拟ip,这个虚拟ip是无法在这里获取的,
    #           但是虚拟ip是路径的一部分,所以这个路径无法拼接出来,所以这里无法配置日志文件路径
    #logfile:
    #  external-file:
#actuator监控:结束

logback-custom.xml
<?xml version="1.0" encoding="UTF-8"?>

<!--
    scan: 当此属性设置为true时,配置文件如果发生改变,将会被重新加载,默认值为true。
    scanPeriod: 设置监测配置文件是否有修改的时间间隔,如果没有给出时间单位,默认单位是毫秒。当scan为true时,此属性生效。默认的时间间隔为1分钟。
    debug: 当此属性设置为true时,将打印出logback内部日志信息,实时查看logback运行状态。默认值为false。
-->
<!-- 输出logback内部日志信息,每隔30s判断一下配置文件有没有更新,若更新,则重新加载 -->
<configuration scan="true" scanPeriod="30 seconds" debug="false">
    <!--从java代码中获取虚拟ip的值-->
    <!--获取当前微服务部署虚拟IP,如rancher为当前微服务分配的ip-->
    <define name="VIRTUAL_IP" class="org.openatom.springcloud.config.VirtualIpConfig"/>

    <!--从Spring容器中获取配置(Spring配置文件加载顺序:bootstrap.yml->logback.xml->application.yml)-->
    <!--获取当前微服务部署机器ip-->
    <springProperty name="MACHINE_IP" scope="context" source="logback.deploy-machine-ip"/>
    <!--应用名称-->
    <springProperty name="LOG_NAME" scope="context" source="logback.log-name"/>
    <!--是否启用append-->
    <springProperty name="IS_APPEND" scope="context" source="logback.append"/>
    <!--是否启用立即刷新-->
    <springProperty name="IS_IMMEDIATEFLUSH" scope="context" source="logback.immediate-flush"/>
    <springProperty name="LOG_PATH" scope="context" source="logging.path"/>
    <!--logstash地址-->
    <springProperty name="LOGSTASH_HOST" scope="context" source="logstash.host"/>
    <!--索引名称-->
    <springProperty name="INDEX_NAME" scope="context" source="logstash.index"/>


    <!-- name:变量的名称,可以随意起名,但建议名字要简明直译;value:变量的值;在配置文件中,我们可以用 ${} 的方式来使用,将变量引入到其他节点中去。-->
    <!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度 %msg:日志消息,%n是换行符-->
    <!--控制台日志输出预选样式-->
    <property name="CONSOLE_LOG_PATTERN_1" value="%red(%d{yyyy-MM-dd HH:mm:ss.SSS}) %green([%thread]) [machineIp:${MACHINE_IP} virtualIp:${VIRTUAL_IP}] [TraceId:%X{X-B3-TraceId:-} SpanId:%X{X-B3-SpanId:-} %highlight(%-5level) %boldMagenta(%logger{10}): %cyan(%msg%n)"/>
    <property name="CONSOLE_LOG_PATTERN_2" value="%yellow(%date{yyyy-MM-dd HH:mm:ss}) [machineIp:${MACHINE_IP} virtualIp:${VIRTUAL_IP}] [TraceId:%X{X-B3-TraceId:-} SpanId:%X{X-B3-SpanId:-} %highlight([%-5level]) %green(%logger) %msg%n"/>
    <property name="CONSOLE_LOG_PATTERN_3" value="%date{yyyy-MM-dd HH:mm:ss} [machineIp:${MACHINE_IP} virtualIp:${VIRTUAL_IP}] [TraceId:%X{X-B3-TraceId:-} SpanId:%X{X-B3-SpanId:-} Span-Export:%X{X-Span-Export:-}]  %green(%-5level) %boldMagenta(${PID:-}) -- [%+20thread] %cyan(%logger{20}) %line       : %msg%n"/>
    <!--文件中日志输出预选样式-->
    <property name="FILE_LOG_PATTERN_1" value="%d{yyyyMMdd:HH:mm:ss.SSS} [machineIp:${MACHINE_IP} virtualIp:${VIRTUAL_IP}] [TraceId:%X{X-B3-TraceId:-} SpanId:%X{X-B3-SpanId:-} [%thread] %-5level  %msg%n"/>

    <!--控制台日志输出格式-->
    <property name="CONSOLE_LOG_PATTERN" value="${CONSOLE_LOG_PATTERN_3}"/>
    <!--文件中日志输出格式-->
    <property name="FILE_LOG_PATTERN" value="${FILE_LOG_PATTERN_1}"/>
    <!--日志名称-->
    <!--定义默认日志输出级别-->
    <property name="LOG_OUTPUT_LEVEL" value="${LOG_LEVEL}" />
    <!--定义默认日志输出编码-->
    <property name="ENCODING" value="UTF-8" />

    <!-- 控制台输出:开始 -->
    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
        <!-- 用来设置日志的输入格式,使用“%+转换符”的方式,如果要输出”%”则必须使用”\”进行转义。-->
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <!-- 格式化输出:https://logback.qos.ch/manual/layouts.html
                 %d 表示日期,
                 %thread 表示线程名,
                 %level 日志级别从左显示5个字符宽度,
                 %t 线程名
                 %file:%line 文件名+行号,
                 %m 日志消息,%n是换行符
                 %X{traceId}:自定义设置的参数,后面会说。
            -->
            <pattern>${CONSOLE_LOG_PATTERN}</pattern>
            <charset>${ENCODING}</charset>
        </encoder>
    </appender>
    <!-- 控制台输出:结束 -->

    <!--输出到文件:开始-->
    <!-- 将项目本次运行INFO日志同步输出到文件,会自动清空文件中上一次的日志 -->
    <appender name="APPENDER-FILEAPPENDER-INFO" class="ch.qos.logback.core.FileAppender">
        <!-- 过滤器,只记录 info 级别以上的日志 -->
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <level>INFO</level>
        </filter>
        <!-- 写入的日志文件名,可以使相对目录也可以是绝对目录,如果上级目录不存在则自动创建 -->
        <file>${LOG_PATH}/${MACHINE_IP}/${VIRTUAL_IP}/${LOG_NAME}-info.log</file>
        <!-- 如果为true表示日志被追加到文件结尾,如果是false表示清空文件 -->
        <append>${IS_APPEND}</append>
        <!--立即刷新,设置成false可以提高日志吞吐量-->
        <immediateFlush>${IS_IMMEDIATEFLUSH}</immediateFlush>
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <pattern>${FILE_LOG_PATTERN}</pattern>
            <charset>${ENCODING}</charset>
        </encoder>
    </appender>

    <!-- 将项目本次运行INFO日志异步输出到文件,会自动清空文件中上一次的日志 -->
    <appender name="ASYNC-APPENDER-FILEAPPENDER-INFO" class="ch.qos.logback.classic.AsyncAppender">
        <appender-ref ref="APPENDER-FILEAPPENDER-INFO" />
        <!-- 设置异步阻塞队列的大小,为了不丢失日志建议设置的大一些,单机压测时100000是没问题的,应该不用担心OOM -->
        <queueSize>10000</queueSize>
        <!-- 设置丢弃DEBUG、TRACE、INFO日志的阀值,不丢失 -->
        <discardingThreshold>0</discardingThreshold>
        <!-- 设置队列入队时非阻塞,当队列满时会直接丢弃日志,但是对性能提升极大 -->
        <neverBlock>${IS_IMMEDIATEFLUSH}</neverBlock>
    </appender>

    <!-- 将项目本次运行DEBUG日志同步输出到文件,会自动清空文件中上一次的日志 -->
    <appender name="APPENDER-FILEAPPENDER-DEBUG" class="ch.qos.logback.core.FileAppender">
        <!-- 过滤器,只记录 info 级别以上的日志 -->
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <level>DEBUG</level>
        </filter>
        <!-- 写入的日志文件名,可以使相对目录也可以是绝对目录,如果上级目录不存在则自动创建 -->
        <file>${LOG_PATH}/${MACHINE_IP}/${VIRTUAL_IP}/${LOG_NAME}-debug.log</file>
        <!-- 如果为true表示日志被追加到文件结尾,如果是false表示清空文件 -->
        <append>${IS_APPEND}</append>
        <!--立即刷新,设置成false可以提高日志吞吐量-->
        <immediateFlush>true</immediateFlush>
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <pattern>${FILE_LOG_PATTERN}</pattern>
            <charset>${ENCODING}</charset>
        </encoder>
    </appender>

    <!-- 将项目本次运行DEBUG日志异步输出到文件,会自动清空文件中上一次的日志 -->
    <appender name="ASYNC-APPENDER-FILEAPPENDER-DEBUG" class="ch.qos.logback.classic.AsyncAppender">
        <appender-ref ref="APPENDER-FILEAPPENDER-DEBUG" />
        <!-- 设置异步阻塞队列的大小,为了不丢失日志建议设置的大一些,单机压测时100000是没问题的,应该不用担心OOM -->
        <queueSize>10000</queueSize>
        <!-- 设置丢弃DEBUG、TRACE、INFO日志的阀值,不丢失 -->
        <discardingThreshold>0</discardingThreshold>
        <!-- 设置队列入队时非阻塞,当队列满时会直接丢弃日志,但是对性能提升极大 -->
        <neverBlock>true</neverBlock>
    </appender>

    <!-- 将项目本次运行ERROR日志同步输出到文件,会自动清空文件中上一次的日志 -->
    <appender name="APPENDER-FILEAPPENDER-ERROR" class="ch.qos.logback.core.FileAppender">
        <!-- 过滤器,只记录 info 级别以上的日志 -->
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <level>DEBUG</level>
        </filter>
        <!-- 写入的日志文件名,可以使相对目录也可以是绝对目录,如果上级目录不存在则自动创建 -->
        <file>${LOG_PATH}/${MACHINE_IP}/${VIRTUAL_IP}/${LOG_NAME}-error.log</file>
        <!-- 如果为true表示日志被追加到文件结尾,如果是false表示清空文件 -->
        <append>${IS_APPEND}</append>
        <!--立即刷新,设置成false可以提高日志吞吐量-->
        <immediateFlush>${IS_IMMEDIATEFLUSH}</immediateFlush>
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <pattern>${FILE_LOG_PATTERN}</pattern>
            <charset>${ENCODING}</charset>
        </encoder>
    </appender>

    <!-- 将项目本次运行ERROR日志异步输出到文件,会自动清空文件中上一次的日志 -->
    <appender name="ASYNC-APPENDER-FILEAPPENDER-ERROR" class="ch.qos.logback.classic.AsyncAppender">
        <appender-ref ref="APPENDER-FILEAPPENDER-ERROR" />
        <!-- 设置异步阻塞队列的大小,为了不丢失日志建议设置的大一些,单机压测时100000是没问题的,应该不用担心OOM -->
        <queueSize>10000</queueSize>
        <!-- 设置丢弃DEBUG、TRACE、INFO日志的阀值,不丢失 -->
        <discardingThreshold>0</discardingThreshold>
        <!-- 设置队列入队时非阻塞,当队列满时会直接丢弃日志,但是对性能提升极大 -->
        <neverBlock>true</neverBlock>
    </appender>
    <!--输出到文件:结束-->


    <!--滚动输出到文件(按照天保存):开始-->
    <!-- 将项目本次运行INFO日志同步输出到文件,按照每天生成日志文件,会自动拼接上一次日志 -->
    <appender name="APPENDER-ROLLINGFILEAPPENDER-INFO" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <!-- 过滤器,只记录 info 级别以上的日志 -->
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <level>INFO</level>
        </filter>
        <!--立即刷新,设置成false可以提高日志吞吐量-->
        <immediateFlush>false</immediateFlush>
        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
            <!-- 日志文件输出的文件名:
                %d:可以包含一个Java.text.SimpleDateFormat指定的时间格式
                %i:自增数字
            -->
            <fileNamePattern>${LOG_PATH}/${MACHINE_IP}/${VIRTUAL_IP}/HISTORY/${LOG_NAME}-info-%d{yyyy-MM-dd}-index%i.log</fileNamePattern>
            <!-- 日志文件保存历史数量:控制保留的归档文件的最大数量,如果超出数量就删除旧文件 -->
            <maxHistory>10</maxHistory>
            <!-- 文件大小超过100MB归档 -->
            <maxFileSize>20MB</maxFileSize>
        </rollingPolicy>
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <pattern>${FILE_LOG_PATTERN}</pattern>
            <charset>${ENCODING}</charset>
        </encoder>
    </appender>

    <!-- 将项目本次运行INFO日志异步输出到文件,按照每天生成日志文件,会自动拼接上一次日志 -->
    <appender name="ASYNC-APPENDER-ROLLINGFILEAPPENDER-INFO" class="ch.qos.logback.classic.AsyncAppender">
        <appender-ref ref="APPENDER-ROLLINGFILEAPPENDER-INFO" />
        <!-- 设置异步阻塞队列的大小,为了不丢失日志建议设置的大一些,单机压测时100000是没问题的,应该不用担心OOM -->
        <queueSize>10000</queueSize>
        <!-- 设置丢弃DEBUG、TRACE、INFO日志的阀值,不丢失 -->
        <discardingThreshold>0</discardingThreshold>
        <!-- 设置队列入队时非阻塞,当队列满时会直接丢弃日志,但是对性能提升极大 -->
        <neverBlock>true</neverBlock>
    </appender>

    <!-- 将项目本次运行DEBUG日志同步输出到文件,按照每天生成日志文件,会自动拼接上一次日志 -->
    <appender name="APPENDER-ROLLINGFILEAPPENDER-DEBUG" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <!-- 过滤器,只记录 info 级别以上的日志 -->
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <level>DEBUG</level>
        </filter>
        <!--立即刷新,设置成false可以提高日志吞吐量-->
        <immediateFlush>false</immediateFlush>
        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
            <!-- 日志文件输出的文件名:
                %d:可以包含一个Java.text.SimpleDateFormat指定的时间格式
                %i:自增数字
            -->
            <fileNamePattern>${LOG_PATH}/${MACHINE_IP}/${VIRTUAL_IP}/HISTORY/${LOG_NAME}-debug-%d{yyyy-MM-dd}-index%i.log</fileNamePattern>
            <!-- 日志文件保存历史数量:控制保留的归档文件的最大数量,如果超出数量就删除旧文件 -->
            <maxHistory>10</maxHistory>
            <!-- 文件大小超过100MB归档 -->
            <maxFileSize>20MB</maxFileSize>
        </rollingPolicy>
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <pattern>${FILE_LOG_PATTERN}</pattern>
            <charset>${ENCODING}</charset>
        </encoder>
    </appender>

    <!-- 将项目本次运行DEBUG日志异步输出到文件,按照每天生成日志文件,会自动拼接上一次日志 -->
    <appender name="ASYNC-APPENDER-ROLLINGFILEAPPENDER-DEBUG" class="ch.qos.logback.classic.AsyncAppender">
        <appender-ref ref="APPENDER-ROLLINGFILEAPPENDER-DEBUG" />
        <!-- 设置异步阻塞队列的大小,为了不丢失日志建议设置的大一些,单机压测时100000是没问题的,应该不用担心OOM -->
        <queueSize>10000</queueSize>
        <!-- 设置丢弃DEBUG、TRACE、INFO日志的阀值,不丢失 -->
        <discardingThreshold>0</discardingThreshold>
        <!-- 设置队列入队时非阻塞,当队列满时会直接丢弃日志,但是对性能提升极大 -->
        <neverBlock>true</neverBlock>
    </appender>

    <!-- 将项目本次运行ERROR日志同步输出到文件,按照每天生成日志文件,会自动拼接上一次日志 -->
    <appender name="APPENDER-ROLLINGFILEAPPENDER-ERROR" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <!-- 过滤器,只记录error级别的日志 -->
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>ERROR</level>
            <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>
        <!--立即刷新,设置成false可以提高日志吞吐量-->
        <immediateFlush>false</immediateFlush>
        <!-- 每天生成一个日志文件,保存30天的日志文件 -->
        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
            <!-- 日志文件输出的文件名:按天回滚 daily -->
            <fileNamePattern>${LOG_PATH}/${MACHINE_IP}/${VIRTUAL_IP}/HISTORY/${LOG_NAME}-error-%d{yyyy-MM-dd}-index%i.log</fileNamePattern>
            <!-- 日志文件保留天数 -->
            <maxHistory>10</maxHistory>
            <!-- 文件大小超过100MB归档 -->
            <maxFileSize>20MB</maxFileSize>
        </rollingPolicy>
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <pattern>${FILE_LOG_PATTERN}</pattern>
            <charset>utf8</charset>
        </encoder>
    </appender>

    <appender name="ASYNC-APPENDER-ROLLINGFILEAPPENDER-ERROR" class="ch.qos.logback.classic.AsyncAppender">
        <appender-ref ref="APPENDER-ROLLINGFILEAPPENDER-ERROR" />
        <!-- 设置异步阻塞队列的大小,为了不丢失日志建议设置的大一些,单机压测时100000是没问题的,应该不用担心OOM -->
        <queueSize>10000</queueSize>
        <!-- 设置丢弃DEBUG、TRACE、INFO日志的阀值,不丢失 -->
        <discardingThreshold>0</discardingThreshold>
        <!-- 设置队列入队时非阻塞,当队列满时会直接丢弃日志,但是对性能提升极大 -->
        <neverBlock>true</neverBlock>
    </appender>
    <!--滚动输出到文件(按照天保存):结束-->

    <!--输出到LOGSTASH:开始-->
    <!-- 将项目本次运行ERROR日志同步输出到文件,按照每天生成日志文件,会自动拼接上一次日志 -->
    <appender name="APPENDER-LOGSTASH" class="net.logstash.logback.appender.LogstashTcpSocketAppender">
        <!--  logstash服务器地址-->
        <destination>${LOGSTASH_HOST}</destination>
        <encoder class="net.logstash.logback.encoder.LoggingEventCompositeJsonEncoder">
            <providers>
                <pattern>
                    <pattern>
                        {
                        "appName":"${INDEX_NAME}",
                        "machineIp":"${MACHINE_IP}",
                        "virtualIp":"${VIRTUAL_IP}",
                        "serviceName":"${LOG_NAME}",
                        "timestamp": "%date{\"yyyy-MM-dd'T'HH:mm:ss,SSSZ\"}",
                        "logLevel":"%level",
                        "message":"%msg%n",
                        "traceId": "%X{X-B3-TraceId:-}",
                        "spanId": "%X{X-B3-SpanId:-}",
                        "spanExport": "%X{X-Span-Export:-}"
                        }
                    </pattern>
                </pattern>
            </providers>
        </encoder>
    </appender>
    <appender name="ASYNC-APPENDER-LOGSTASH" class="ch.qos.logback.classic.AsyncAppender">
        <appender-ref ref="APPENDER-LOGSTASH" />
        <!-- 设置异步阻塞队列的大小,为了不丢失日志建议设置的大一些,单机压测时100000是没问题的,应该不用担心OOM -->
        <queueSize>10000</queueSize>
        <!-- 设置丢弃DEBUG、TRACE、INFO日志的阀值,不丢失 -->
        <discardingThreshold>0</discardingThreshold>
        <!-- 设置队列入队时非阻塞,当队列满时会直接丢弃日志,但是对性能提升极大 -->
        <neverBlock>true</neverBlock>
    </appender>
    <!--输出到logstash:结束-->

    <!--
        开发环境日志级别为DEBUG
        level:用来设置打印级别
        五个常用打印级别从低至高依次为TRACE、DEBUG、INFO、WARN、ERROR
    -->
    <springProfile name="dev">
        <root>
            <!--输出到控制台-->
            <appender-ref ref="STDOUT"/>
            <!--异步非滚动输出到文件-->
            <appender-ref ref="ASYNC-APPENDER-FILEAPPENDER-INFO"/>
            <appender-ref ref="ASYNC-APPENDER-FILEAPPENDER-DEBUG"/>
            <appender-ref ref="ASYNC-APPENDER-FILEAPPENDER-ERROR"/>
            <!--异步滚动输出到文件:dev环境不开启-->
<!--            <appender-ref ref="ASYNC-APPENDER-ROLLINGFILEAPPENDER-INFO"/>-->
<!--            <appender-ref ref="ASYNC-APPENDER-ROLLINGFILEAPPENDER-DEBUG"/>-->
<!--            <appender-ref ref="ASYNC-APPENDER-ROLLINGFILEAPPENDER-ERROR"/>-->
            <!--异步滚动输出到logstash-->
            <appender-ref ref="ASYNC-APPENDER-LOGSTASH"/>
        </root>
    </springProfile>

    <!-- 测试环境日志级别为INFO -->
    <springProfile name="test">
        <root>
            <!--输出到控制台-->
            <appender-ref ref="STDOUT"/>
            <!--异步非滚动输出到文件-->
            <appender-ref ref="ASYNC-APPENDER-FILEAPPENDER-INFO"/>
            <appender-ref ref="ASYNC-APPENDER-FILEAPPENDER-DEBUG"/>
            <appender-ref ref="ASYNC-APPENDER-FILEAPPENDER-ERROR"/>
            <!--异步滚动输出到文件:test环境不开启-->
<!--            <appender-ref ref="ASYNC-APPENDER-ROLLINGFILEAPPENDER-INFO"/>-->
<!--            <appender-ref ref="ASYNC-APPENDER-ROLLINGFILEAPPENDER-DEBUG"/>-->
<!--            <appender-ref ref="ASYNC-APPENDER-ROLLINGFILEAPPENDER-ERROR"/>-->
            <!--异步滚动输出到logstash-->
            <appender-ref ref="ASYNC-APPENDER-LOGSTASH"/>
        </root>
    </springProfile>

    <!-- 生产环境日志级别为INFO -->
    <springProfile name="prod">
        <root>
            <!--输出到控制台-->
            <appender-ref ref="STDOUT"/>
            <!--异步非滚动输出到文件-->
            <appender-ref ref="ASYNC-APPENDER-FILEAPPENDER-INFO"/>
            <appender-ref ref="ASYNC-APPENDER-FILEAPPENDER-DEBUG"/>
            <appender-ref ref="ASYNC-APPENDER-FILEAPPENDER-ERROR"/>
            <!--异步滚动输出到文件-->
            <appender-ref ref="ASYNC-APPENDER-ROLLINGFILEAPPENDER-INFO"/>
            <appender-ref ref="ASYNC-APPENDER-ROLLINGFILEAPPENDER-DEBUG"/>
            <appender-ref ref="ASYNC-APPENDER-ROLLINGFILEAPPENDER-ERROR"/>
            <!--异步滚动输出到logstash-->
            <appender-ref ref="ASYNC-APPENDER-LOGSTASH"/>
        </root>
    </springProfile>

    <!-- rancher环境日志级别为INFO -->
    <springProfile name="rancher">
        <root>
            <!--输出到控制台-->
            <appender-ref ref="STDOUT"/>
            <!--异步非滚动输出到文件-->
            <appender-ref ref="ASYNC-APPENDER-FILEAPPENDER-INFO"/>
            <appender-ref ref="ASYNC-APPENDER-FILEAPPENDER-DEBUG"/>
            <appender-ref ref="ASYNC-APPENDER-FILEAPPENDER-ERROR"/>
            <!--异步滚动输出到文件-->
            <appender-ref ref="ASYNC-APPENDER-ROLLINGFILEAPPENDER-INFO"/>
            <appender-ref ref="ASYNC-APPENDER-ROLLINGFILEAPPENDER-DEBUG"/>
            <appender-ref ref="ASYNC-APPENDER-ROLLINGFILEAPPENDER-ERROR"/>
            <!--异步滚动输出到logstash-->
            <appender-ref ref="ASYNC-APPENDER-LOGSTASH"/>
        </root>
    </springProfile>
</configuration>

PaymentMapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >

<mapper namespace="org.openatom.springcloud.dao.PaymentDao">

    <!--第一种写法:parameterType不写全路径-->
    <insert id="create" parameterType="Payment" useGeneratedKeys="true" keyProperty="id">
        insert into payment(serial)  values(#{serial});
    </insert>

    <resultMap id="BaseResultMap" type="Payment">
        <id column="id" property="id" jdbcType="BIGINT"/>
        <id column="serial" property="serial" jdbcType="VARCHAR"/>
    </resultMap>
    <select id="getPaymentById" parameterType="Long" resultMap="BaseResultMap">
        select * from payment where id=#{id};
    </select>

    <!--第二种写法:parameterType的写法与第一种有区别-->
    <!--
    <insert id="create" parameterType="org.openatom.springcloud.entities.Payment" useGeneratedKeys="true" keyProperty="id">
        insert into payment(serial)  values(#{serial});
    </insert>

    <resultMap id="BaseResultMap" type="org.openatom.springcloud.entities.Payment">
        <id column="id" property="id" jdbcType="BIGINT"/>
        <id column="serial" property="serial" jdbcType="VARCHAR"/>
    </resultMap>
    <select id="getPaymentById" parameterType="Long" resultMap="BaseResultMap">
        select * from payment where id=#{id};
    </select>
    -->
</mapper>



prod环境配置文件
application.yml
#设置spring项目运行的环境
spring:
  profiles:
    active: '@profile.active@'


application-prod.yml
server:
  port: 8009 #访问端口
spring:
  application:
    name: SPRINGCLOUD-BASIC-SAMPLE-PROVIDER-PAYMENT-SERVICE-CLUSTER-PROD  #注意:服务名不要出现_
  devtools: #热部署开关
    restart:
      enabled: true
  # 将Client作为服务注册到SpringBootAdmin Server端,通过Server来监听项目的运行情况
  boot:
    admin:
      client:
        url: http://192.168.0.4:${server.port}
  logging:
    level: info
  datasource:
    type: com.alibaba.druid.pool.DruidDataSource            # 当前数据源操作类型
    driver-class-name: com.mysql.cj.jdbc.Driver              # mysql驱动包
    url: jdbc:mysql://192.168.0.5:3306/payment?useUnicode=true&characterEncoding=utf-8&useSSL=false
    username: root
    password: Mysql123456

eureka:
  client:
    register-with-eureka: true  #表示是否将自己注册进EurekaServer默认为true。
    fetchRegistry: true  #是否从EurekaServer抓取已有的注册信息,默认为true。单节点无所谓,集群必须设置为true才能配合ribbon使用负载均衡
    service-url:
      #单机版
      defaultZone: http://192.168.0.4:7005/eureka
      #集群版
      #defaultZone: http://eureka7002:7002/eureka,http://eureka7003:7003/eureka,http://eureka7004:7004/eureka
  instance:
    instance-id: SPRINGCLOUD-PROVIDER-PAYMENT-SERVICE-CLUSTER-NODE-PAYMENT8009-PROD #Eureka仪表盘中Instances currently registered with Eureka.Status显示的内容
    #当前微服务所在部署机器ip
    ip-address: 192.168.0.4
    prefer-ip-address: true  #访问路径可以显示IP地址,点击Eureka仪表盘中Instances currently registered with Eureka.Status显示的内容地址栏是否显示IP地址
    lease-renewal-interval-in-seconds: 30 #Eureka客户端向服务端发送心跳的时间间隔,单位为秒(默认是30秒)
    lease-expiration-duration-in-seconds: 90 #Eureka服务端在收到最后一次心跳后等待时间上限,单位为秒(默认是90秒),超时将剔除服务

mybatis:
  mapperLocations: classpath:mapper/*.xml
  type-aliases-package: org.openatom.springcloud.entities    # 所有Entity别名类所在包


#配置文件修改说明-------------------------------------------------:开始
#注意:不同的部署环境需要修改的配置
#   1.${logback.path}  #修改日志存放位置,Linxu为/,Windows为\
#       修改原因: Linux和Windows目录结构不同
#配置文件修改说明-------------------------------------------------:结束

#自定义日志配置文件路径
logging:
  config: classpath:logback-custom.xml
  path: /logs #所有日志存放在位置,加上\方便Linux环境下配置
  level:
    root: info #全局日志输出级别

logback:
  log-name: ${spring.application.name}
  append: false #是否启用append(追加到已经存在日志文件尾部),true:重启项目会追加新日志到之前日志,false:重启项目会清空之前的日志
  immediate-flush: true #是否启用immediateFlush(立即刷新),true:重启项目自动追加,false:重启项目会情况之前的日志
  deploy-machine-ip: ${eureka.instance.ip-address} #当前微服务所在部署机器ip

#logstash相关配置:开始
logstash:
  host: 192.168.0.4:5044 # logstash地址
  index: '@project.parent.artifactId@' # es中index名称
#logstash相关配置:结束

#actuator监控:开始
#通过下面的配置启用所有的监控端点,默认情况下,这些端点是禁用的;
management:
  endpoints:
    web:
      exposure:
        include: '*'
    enabled-by-default: true
  endpoint:
    health:
      show-details: always # 访问/actuator/health时,显示详细信息,而不是仅仅显示"status": "UP"
    # 日志文件路径:特别注意,此处无法配置日志文件路径,因为rancher会生成虚拟ip,这个虚拟ip是无法在这里获取的,
    #           但是虚拟ip是路径的一部分,所以这个路径无法拼接出来,所以这里无法配置日志文件路径
    #logfile:
    #  external-file:
#actuator监控:结束

logback-custom.xml
<?xml version="1.0" encoding="UTF-8"?>

<!--
    scan: 当此属性设置为true时,配置文件如果发生改变,将会被重新加载,默认值为true。
    scanPeriod: 设置监测配置文件是否有修改的时间间隔,如果没有给出时间单位,默认单位是毫秒。当scan为true时,此属性生效。默认的时间间隔为1分钟。
    debug: 当此属性设置为true时,将打印出logback内部日志信息,实时查看logback运行状态。默认值为false。
-->
<!-- 输出logback内部日志信息,每隔30s判断一下配置文件有没有更新,若更新,则重新加载 -->
<configuration scan="true" scanPeriod="30 seconds" debug="false">
    <!--从java代码中获取虚拟ip的值-->
    <!--获取当前微服务部署虚拟IP,如rancher为当前微服务分配的ip-->
    <define name="VIRTUAL_IP" class="org.openatom.springcloud.config.VirtualIpConfig"/>

    <!--从Spring容器中获取配置(Spring配置文件加载顺序:bootstrap.yml->logback.xml->application.yml)-->
    <!--获取当前微服务部署机器ip-->
    <springProperty name="MACHINE_IP" scope="context" source="logback.deploy-machine-ip"/>
    <!--应用名称-->
    <springProperty name="LOG_NAME" scope="context" source="logback.log-name"/>
    <!--是否启用append-->
    <springProperty name="IS_APPEND" scope="context" source="logback.append"/>
    <!--是否启用立即刷新-->
    <springProperty name="IS_IMMEDIATEFLUSH" scope="context" source="logback.immediate-flush"/>
    <springProperty name="LOG_PATH" scope="context" source="logging.path"/>
    <!--logstash地址-->
    <springProperty name="LOGSTASH_HOST" scope="context" source="logstash.host"/>
    <!--索引名称-->
    <springProperty name="INDEX_NAME" scope="context" source="logstash.index"/>


    <!-- name:变量的名称,可以随意起名,但建议名字要简明直译;value:变量的值;在配置文件中,我们可以用 ${} 的方式来使用,将变量引入到其他节点中去。-->
    <!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度 %msg:日志消息,%n是换行符-->
    <!--控制台日志输出预选样式-->
    <property name="CONSOLE_LOG_PATTERN_1" value="%red(%d{yyyy-MM-dd HH:mm:ss.SSS}) %green([%thread]) [machineIp:${MACHINE_IP} virtualIp:${VIRTUAL_IP}] [TraceId:%X{X-B3-TraceId:-} SpanId:%X{X-B3-SpanId:-} %highlight(%-5level) %boldMagenta(%logger{10}): %cyan(%msg%n)"/>
    <property name="CONSOLE_LOG_PATTERN_2" value="%yellow(%date{yyyy-MM-dd HH:mm:ss}) [machineIp:${MACHINE_IP} virtualIp:${VIRTUAL_IP}] [TraceId:%X{X-B3-TraceId:-} SpanId:%X{X-B3-SpanId:-} %highlight([%-5level]) %green(%logger) %msg%n"/>
    <property name="CONSOLE_LOG_PATTERN_3" value="%date{yyyy-MM-dd HH:mm:ss} [machineIp:${MACHINE_IP} virtualIp:${VIRTUAL_IP}] [TraceId:%X{X-B3-TraceId:-} SpanId:%X{X-B3-SpanId:-} Span-Export:%X{X-Span-Export:-}]  %green(%-5level) %boldMagenta(${PID:-}) -- [%+20thread] %cyan(%logger{20}) %line       : %msg%n"/>
    <!--文件中日志输出预选样式-->
    <property name="FILE_LOG_PATTERN_1" value="%d{yyyyMMdd:HH:mm:ss.SSS} [machineIp:${MACHINE_IP} virtualIp:${VIRTUAL_IP}] [TraceId:%X{X-B3-TraceId:-} SpanId:%X{X-B3-SpanId:-} [%thread] %-5level  %msg%n"/>

    <!--控制台日志输出格式-->
    <property name="CONSOLE_LOG_PATTERN" value="${CONSOLE_LOG_PATTERN_3}"/>
    <!--文件中日志输出格式-->
    <property name="FILE_LOG_PATTERN" value="${FILE_LOG_PATTERN_1}"/>
    <!--日志名称-->
    <!--定义默认日志输出级别-->
    <property name="LOG_OUTPUT_LEVEL" value="${LOG_LEVEL}" />
    <!--定义默认日志输出编码-->
    <property name="ENCODING" value="UTF-8" />

    <!-- 控制台输出:开始 -->
    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
        <!-- 用来设置日志的输入格式,使用“%+转换符”的方式,如果要输出”%”则必须使用”\”进行转义。-->
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <!-- 格式化输出:https://logback.qos.ch/manual/layouts.html
                 %d 表示日期,
                 %thread 表示线程名,
                 %level 日志级别从左显示5个字符宽度,
                 %t 线程名
                 %file:%line 文件名+行号,
                 %m 日志消息,%n是换行符
                 %X{traceId}:自定义设置的参数,后面会说。
            -->
            <pattern>${CONSOLE_LOG_PATTERN}</pattern>
            <charset>${ENCODING}</charset>
        </encoder>
    </appender>
    <!-- 控制台输出:结束 -->

    <!--输出到文件:开始-->
    <!-- 将项目本次运行INFO日志同步输出到文件,会自动清空文件中上一次的日志 -->
    <appender name="APPENDER-FILEAPPENDER-INFO" class="ch.qos.logback.core.FileAppender">
        <!-- 过滤器,只记录 info 级别以上的日志 -->
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <level>INFO</level>
        </filter>
        <!-- 写入的日志文件名,可以使相对目录也可以是绝对目录,如果上级目录不存在则自动创建 -->
        <file>${LOG_PATH}/${MACHINE_IP}/${VIRTUAL_IP}/${LOG_NAME}-info.log</file>
        <!-- 如果为true表示日志被追加到文件结尾,如果是false表示清空文件 -->
        <append>${IS_APPEND}</append>
        <!--立即刷新,设置成false可以提高日志吞吐量-->
        <immediateFlush>${IS_IMMEDIATEFLUSH}</immediateFlush>
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <pattern>${FILE_LOG_PATTERN}</pattern>
            <charset>${ENCODING}</charset>
        </encoder>
    </appender>

    <!-- 将项目本次运行INFO日志异步输出到文件,会自动清空文件中上一次的日志 -->
    <appender name="ASYNC-APPENDER-FILEAPPENDER-INFO" class="ch.qos.logback.classic.AsyncAppender">
        <appender-ref ref="APPENDER-FILEAPPENDER-INFO" />
        <!-- 设置异步阻塞队列的大小,为了不丢失日志建议设置的大一些,单机压测时100000是没问题的,应该不用担心OOM -->
        <queueSize>10000</queueSize>
        <!-- 设置丢弃DEBUG、TRACE、INFO日志的阀值,不丢失 -->
        <discardingThreshold>0</discardingThreshold>
        <!-- 设置队列入队时非阻塞,当队列满时会直接丢弃日志,但是对性能提升极大 -->
        <neverBlock>${IS_IMMEDIATEFLUSH}</neverBlock>
    </appender>

    <!-- 将项目本次运行DEBUG日志同步输出到文件,会自动清空文件中上一次的日志 -->
    <appender name="APPENDER-FILEAPPENDER-DEBUG" class="ch.qos.logback.core.FileAppender">
        <!-- 过滤器,只记录 info 级别以上的日志 -->
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <level>DEBUG</level>
        </filter>
        <!-- 写入的日志文件名,可以使相对目录也可以是绝对目录,如果上级目录不存在则自动创建 -->
        <file>${LOG_PATH}/${MACHINE_IP}/${VIRTUAL_IP}/${LOG_NAME}-debug.log</file>
        <!-- 如果为true表示日志被追加到文件结尾,如果是false表示清空文件 -->
        <append>${IS_APPEND}</append>
        <!--立即刷新,设置成false可以提高日志吞吐量-->
        <immediateFlush>true</immediateFlush>
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <pattern>${FILE_LOG_PATTERN}</pattern>
            <charset>${ENCODING}</charset>
        </encoder>
    </appender>

    <!-- 将项目本次运行DEBUG日志异步输出到文件,会自动清空文件中上一次的日志 -->
    <appender name="ASYNC-APPENDER-FILEAPPENDER-DEBUG" class="ch.qos.logback.classic.AsyncAppender">
        <appender-ref ref="APPENDER-FILEAPPENDER-DEBUG" />
        <!-- 设置异步阻塞队列的大小,为了不丢失日志建议设置的大一些,单机压测时100000是没问题的,应该不用担心OOM -->
        <queueSize>10000</queueSize>
        <!-- 设置丢弃DEBUG、TRACE、INFO日志的阀值,不丢失 -->
        <discardingThreshold>0</discardingThreshold>
        <!-- 设置队列入队时非阻塞,当队列满时会直接丢弃日志,但是对性能提升极大 -->
        <neverBlock>true</neverBlock>
    </appender>

    <!-- 将项目本次运行ERROR日志同步输出到文件,会自动清空文件中上一次的日志 -->
    <appender name="APPENDER-FILEAPPENDER-ERROR" class="ch.qos.logback.core.FileAppender">
        <!-- 过滤器,只记录 info 级别以上的日志 -->
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <level>DEBUG</level>
        </filter>
        <!-- 写入的日志文件名,可以使相对目录也可以是绝对目录,如果上级目录不存在则自动创建 -->
        <file>${LOG_PATH}/${MACHINE_IP}/${VIRTUAL_IP}/${LOG_NAME}-error.log</file>
        <!-- 如果为true表示日志被追加到文件结尾,如果是false表示清空文件 -->
        <append>${IS_APPEND}</append>
        <!--立即刷新,设置成false可以提高日志吞吐量-->
        <immediateFlush>${IS_IMMEDIATEFLUSH}</immediateFlush>
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <pattern>${FILE_LOG_PATTERN}</pattern>
            <charset>${ENCODING}</charset>
        </encoder>
    </appender>

    <!-- 将项目本次运行ERROR日志异步输出到文件,会自动清空文件中上一次的日志 -->
    <appender name="ASYNC-APPENDER-FILEAPPENDER-ERROR" class="ch.qos.logback.classic.AsyncAppender">
        <appender-ref ref="APPENDER-FILEAPPENDER-ERROR" />
        <!-- 设置异步阻塞队列的大小,为了不丢失日志建议设置的大一些,单机压测时100000是没问题的,应该不用担心OOM -->
        <queueSize>10000</queueSize>
        <!-- 设置丢弃DEBUG、TRACE、INFO日志的阀值,不丢失 -->
        <discardingThreshold>0</discardingThreshold>
        <!-- 设置队列入队时非阻塞,当队列满时会直接丢弃日志,但是对性能提升极大 -->
        <neverBlock>true</neverBlock>
    </appender>
    <!--输出到文件:结束-->


    <!--滚动输出到文件(按照天保存):开始-->
    <!-- 将项目本次运行INFO日志同步输出到文件,按照每天生成日志文件,会自动拼接上一次日志 -->
    <appender name="APPENDER-ROLLINGFILEAPPENDER-INFO" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <!-- 过滤器,只记录 info 级别以上的日志 -->
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <level>INFO</level>
        </filter>
        <!--立即刷新,设置成false可以提高日志吞吐量-->
        <immediateFlush>false</immediateFlush>
        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
            <!-- 日志文件输出的文件名:
                %d:可以包含一个Java.text.SimpleDateFormat指定的时间格式
                %i:自增数字
            -->
            <fileNamePattern>${LOG_PATH}/${MACHINE_IP}/${VIRTUAL_IP}/HISTORY/${LOG_NAME}-info-%d{yyyy-MM-dd}-index%i.log</fileNamePattern>
            <!-- 日志文件保存历史数量:控制保留的归档文件的最大数量,如果超出数量就删除旧文件 -->
            <maxHistory>10</maxHistory>
            <!-- 文件大小超过100MB归档 -->
            <maxFileSize>20MB</maxFileSize>
        </rollingPolicy>
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <pattern>${FILE_LOG_PATTERN}</pattern>
            <charset>${ENCODING}</charset>
        </encoder>
    </appender>

    <!-- 将项目本次运行INFO日志异步输出到文件,按照每天生成日志文件,会自动拼接上一次日志 -->
    <appender name="ASYNC-APPENDER-ROLLINGFILEAPPENDER-INFO" class="ch.qos.logback.classic.AsyncAppender">
        <appender-ref ref="APPENDER-ROLLINGFILEAPPENDER-INFO" />
        <!-- 设置异步阻塞队列的大小,为了不丢失日志建议设置的大一些,单机压测时100000是没问题的,应该不用担心OOM -->
        <queueSize>10000</queueSize>
        <!-- 设置丢弃DEBUG、TRACE、INFO日志的阀值,不丢失 -->
        <discardingThreshold>0</discardingThreshold>
        <!-- 设置队列入队时非阻塞,当队列满时会直接丢弃日志,但是对性能提升极大 -->
        <neverBlock>true</neverBlock>
    </appender>

    <!-- 将项目本次运行DEBUG日志同步输出到文件,按照每天生成日志文件,会自动拼接上一次日志 -->
    <appender name="APPENDER-ROLLINGFILEAPPENDER-DEBUG" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <!-- 过滤器,只记录 info 级别以上的日志 -->
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <level>DEBUG</level>
        </filter>
        <!--立即刷新,设置成false可以提高日志吞吐量-->
        <immediateFlush>false</immediateFlush>
        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
            <!-- 日志文件输出的文件名:
                %d:可以包含一个Java.text.SimpleDateFormat指定的时间格式
                %i:自增数字
            -->
            <fileNamePattern>${LOG_PATH}/${MACHINE_IP}/${VIRTUAL_IP}/HISTORY/${LOG_NAME}-debug-%d{yyyy-MM-dd}-index%i.log</fileNamePattern>
            <!-- 日志文件保存历史数量:控制保留的归档文件的最大数量,如果超出数量就删除旧文件 -->
            <maxHistory>10</maxHistory>
            <!-- 文件大小超过100MB归档 -->
            <maxFileSize>20MB</maxFileSize>
        </rollingPolicy>
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <pattern>${FILE_LOG_PATTERN}</pattern>
            <charset>${ENCODING}</charset>
        </encoder>
    </appender>

    <!-- 将项目本次运行DEBUG日志异步输出到文件,按照每天生成日志文件,会自动拼接上一次日志 -->
    <appender name="ASYNC-APPENDER-ROLLINGFILEAPPENDER-DEBUG" class="ch.qos.logback.classic.AsyncAppender">
        <appender-ref ref="APPENDER-ROLLINGFILEAPPENDER-DEBUG" />
        <!-- 设置异步阻塞队列的大小,为了不丢失日志建议设置的大一些,单机压测时100000是没问题的,应该不用担心OOM -->
        <queueSize>10000</queueSize>
        <!-- 设置丢弃DEBUG、TRACE、INFO日志的阀值,不丢失 -->
        <discardingThreshold>0</discardingThreshold>
        <!-- 设置队列入队时非阻塞,当队列满时会直接丢弃日志,但是对性能提升极大 -->
        <neverBlock>true</neverBlock>
    </appender>

    <!-- 将项目本次运行ERROR日志同步输出到文件,按照每天生成日志文件,会自动拼接上一次日志 -->
    <appender name="APPENDER-ROLLINGFILEAPPENDER-ERROR" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <!-- 过滤器,只记录error级别的日志 -->
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>ERROR</level>
            <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>
        <!--立即刷新,设置成false可以提高日志吞吐量-->
        <immediateFlush>false</immediateFlush>
        <!-- 每天生成一个日志文件,保存30天的日志文件 -->
        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
            <!-- 日志文件输出的文件名:按天回滚 daily -->
            <fileNamePattern>${LOG_PATH}/${MACHINE_IP}/${VIRTUAL_IP}/HISTORY/${LOG_NAME}-error-%d{yyyy-MM-dd}-index%i.log</fileNamePattern>
            <!-- 日志文件保留天数 -->
            <maxHistory>10</maxHistory>
            <!-- 文件大小超过100MB归档 -->
            <maxFileSize>20MB</maxFileSize>
        </rollingPolicy>
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <pattern>${FILE_LOG_PATTERN}</pattern>
            <charset>utf8</charset>
        </encoder>
    </appender>

    <appender name="ASYNC-APPENDER-ROLLINGFILEAPPENDER-ERROR" class="ch.qos.logback.classic.AsyncAppender">
        <appender-ref ref="APPENDER-ROLLINGFILEAPPENDER-ERROR" />
        <!-- 设置异步阻塞队列的大小,为了不丢失日志建议设置的大一些,单机压测时100000是没问题的,应该不用担心OOM -->
        <queueSize>10000</queueSize>
        <!-- 设置丢弃DEBUG、TRACE、INFO日志的阀值,不丢失 -->
        <discardingThreshold>0</discardingThreshold>
        <!-- 设置队列入队时非阻塞,当队列满时会直接丢弃日志,但是对性能提升极大 -->
        <neverBlock>true</neverBlock>
    </appender>
    <!--滚动输出到文件(按照天保存):结束-->

    <!--输出到LOGSTASH:开始-->
    <!-- 将项目本次运行ERROR日志同步输出到文件,按照每天生成日志文件,会自动拼接上一次日志 -->
    <appender name="APPENDER-LOGSTASH" class="net.logstash.logback.appender.LogstashTcpSocketAppender">
        <!--  logstash服务器地址-->
        <destination>${LOGSTASH_HOST}</destination>
        <encoder class="net.logstash.logback.encoder.LoggingEventCompositeJsonEncoder">
            <providers>
                <pattern>
                    <pattern>
                        {
                        "appName":"${INDEX_NAME}",
                        "machineIp":"${MACHINE_IP}",
                        "virtualIp":"${VIRTUAL_IP}",
                        "serviceName":"${LOG_NAME}",
                        "timestamp": "%date{\"yyyy-MM-dd'T'HH:mm:ss,SSSZ\"}",
                        "logLevel":"%level",
                        "message":"%msg%n",
                        "traceId": "%X{X-B3-TraceId:-}",
                        "spanId": "%X{X-B3-SpanId:-}",
                        "spanExport": "%X{X-Span-Export:-}"
                        }
                    </pattern>
                </pattern>
            </providers>
        </encoder>
    </appender>
    <appender name="ASYNC-APPENDER-LOGSTASH" class="ch.qos.logback.classic.AsyncAppender">
        <appender-ref ref="APPENDER-LOGSTASH" />
        <!-- 设置异步阻塞队列的大小,为了不丢失日志建议设置的大一些,单机压测时100000是没问题的,应该不用担心OOM -->
        <queueSize>10000</queueSize>
        <!-- 设置丢弃DEBUG、TRACE、INFO日志的阀值,不丢失 -->
        <discardingThreshold>0</discardingThreshold>
        <!-- 设置队列入队时非阻塞,当队列满时会直接丢弃日志,但是对性能提升极大 -->
        <neverBlock>true</neverBlock>
    </appender>
    <!--输出到logstash:结束-->

    <!--
        开发环境日志级别为DEBUG
        level:用来设置打印级别
        五个常用打印级别从低至高依次为TRACE、DEBUG、INFO、WARN、ERROR
    -->
    <springProfile name="dev">
        <root>
            <!--输出到控制台-->
            <appender-ref ref="STDOUT"/>
            <!--异步非滚动输出到文件-->
            <appender-ref ref="ASYNC-APPENDER-FILEAPPENDER-INFO"/>
            <appender-ref ref="ASYNC-APPENDER-FILEAPPENDER-DEBUG"/>
            <appender-ref ref="ASYNC-APPENDER-FILEAPPENDER-ERROR"/>
            <!--异步滚动输出到文件:dev环境不开启-->
<!--            <appender-ref ref="ASYNC-APPENDER-ROLLINGFILEAPPENDER-INFO"/>-->
<!--            <appender-ref ref="ASYNC-APPENDER-ROLLINGFILEAPPENDER-DEBUG"/>-->
<!--            <appender-ref ref="ASYNC-APPENDER-ROLLINGFILEAPPENDER-ERROR"/>-->
            <!--异步滚动输出到logstash-->
            <appender-ref ref="ASYNC-APPENDER-LOGSTASH"/>
        </root>
    </springProfile>

    <!-- 测试环境日志级别为INFO -->
    <springProfile name="test">
        <root>
            <!--输出到控制台-->
            <appender-ref ref="STDOUT"/>
            <!--异步非滚动输出到文件-->
            <appender-ref ref="ASYNC-APPENDER-FILEAPPENDER-INFO"/>
            <appender-ref ref="ASYNC-APPENDER-FILEAPPENDER-DEBUG"/>
            <appender-ref ref="ASYNC-APPENDER-FILEAPPENDER-ERROR"/>
            <!--异步滚动输出到文件:test环境不开启-->
<!--            <appender-ref ref="ASYNC-APPENDER-ROLLINGFILEAPPENDER-INFO"/>-->
<!--            <appender-ref ref="ASYNC-APPENDER-ROLLINGFILEAPPENDER-DEBUG"/>-->
<!--            <appender-ref ref="ASYNC-APPENDER-ROLLINGFILEAPPENDER-ERROR"/>-->
            <!--异步滚动输出到logstash-->
            <appender-ref ref="ASYNC-APPENDER-LOGSTASH"/>
        </root>
    </springProfile>

    <!-- 生产环境日志级别为INFO -->
    <springProfile name="prod">
        <root>
            <!--输出到控制台-->
            <appender-ref ref="STDOUT"/>
            <!--异步非滚动输出到文件-->
            <appender-ref ref="ASYNC-APPENDER-FILEAPPENDER-INFO"/>
            <appender-ref ref="ASYNC-APPENDER-FILEAPPENDER-DEBUG"/>
            <appender-ref ref="ASYNC-APPENDER-FILEAPPENDER-ERROR"/>
            <!--异步滚动输出到文件-->
            <appender-ref ref="ASYNC-APPENDER-ROLLINGFILEAPPENDER-INFO"/>
            <appender-ref ref="ASYNC-APPENDER-ROLLINGFILEAPPENDER-DEBUG"/>
            <appender-ref ref="ASYNC-APPENDER-ROLLINGFILEAPPENDER-ERROR"/>
            <!--异步滚动输出到logstash-->
            <appender-ref ref="ASYNC-APPENDER-LOGSTASH"/>
        </root>
    </springProfile>

    <!-- rancher环境日志级别为INFO -->
    <springProfile name="rancher">
        <root>
            <!--输出到控制台-->
            <appender-ref ref="STDOUT"/>
            <!--异步非滚动输出到文件-->
            <appender-ref ref="ASYNC-APPENDER-FILEAPPENDER-INFO"/>
            <appender-ref ref="ASYNC-APPENDER-FILEAPPENDER-DEBUG"/>
            <appender-ref ref="ASYNC-APPENDER-FILEAPPENDER-ERROR"/>
            <!--异步滚动输出到文件-->
            <appender-ref ref="ASYNC-APPENDER-ROLLINGFILEAPPENDER-INFO"/>
            <appender-ref ref="ASYNC-APPENDER-ROLLINGFILEAPPENDER-DEBUG"/>
            <appender-ref ref="ASYNC-APPENDER-ROLLINGFILEAPPENDER-ERROR"/>
            <!--异步滚动输出到logstash-->
            <appender-ref ref="ASYNC-APPENDER-LOGSTASH"/>
        </root>
    </springProfile>
</configuration>

PaymentMapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >

<mapper namespace="org.openatom.springcloud.dao.PaymentDao">

    <!--第一种写法:parameterType不写全路径-->
    <insert id="create" parameterType="Payment" useGeneratedKeys="true" keyProperty="id">
        insert into payment(serial)  values(#{serial});
    </insert>

    <resultMap id="BaseResultMap" type="Payment">
        <id column="id" property="id" jdbcType="BIGINT"/>
        <id column="serial" property="serial" jdbcType="VARCHAR"/>
    </resultMap>
    <select id="getPaymentById" parameterType="Long" resultMap="BaseResultMap">
        select * from payment where id=#{id};
    </select>

    <!--第二种写法:parameterType的写法与第一种有区别-->
    <!--
    <insert id="create" parameterType="org.openatom.springcloud.entities.Payment" useGeneratedKeys="true" keyProperty="id">
        insert into payment(serial)  values(#{serial});
    </insert>

    <resultMap id="BaseResultMap" type="org.openatom.springcloud.entities.Payment">
        <id column="id" property="id" jdbcType="BIGINT"/>
        <id column="serial" property="serial" jdbcType="VARCHAR"/>
    </resultMap>
    <select id="getPaymentById" parameterType="Long" resultMap="BaseResultMap">
        select * from payment where id=#{id};
    </select>
    -->
</mapper>



rancher环境配置文件
application.yml
#设置spring项目运行的环境
spring:
  profiles:
    active: '@profile.active@'


application-rancher.yml
server:
  port: 8009 #访问端口
spring:
  application:
    name: SPRINGCLOUD-BASIC-SAMPLE-PROVIDER-PAYMENT-SERVICE-CLUSTER-RANCHER  #注意:服务名不要出现_
  devtools: #热部署开关
    restart:
      enabled: true
  # 将Client作为服务注册到SpringBootAdmin Server端,通过Server来监听项目的运行情况
  boot:
    admin:
      client:
        url: http://192.168.0.4:${server.port}
  logging:
    level: info
  datasource:
    type: com.alibaba.druid.pool.DruidDataSource            # 当前数据源操作类型
    driver-class-name: com.mysql.cj.jdbc.Driver              # mysql驱动包
    url: jdbc:mysql://192.168.0.5:3306/payment?useUnicode=true&characterEncoding=utf-8&useSSL=false&allowPublicKeyRetrieval=true
    username: root
    password: Mysql123456_

eureka:
  client:
    register-with-eureka: true  #表示是否将自己注册进EurekaServer默认为true。
    fetchRegistry: true  #是否从EurekaServer抓取已有的注册信息,默认为true。单节点无所谓,集群必须设置为true才能配合ribbon使用负载均衡
    service-url:
      #单机版
      defaultZone: http://192.168.0.4:7005/eureka
      #集群版
      #defaultZone: http://eureka7002:7002/eureka,http://eureka7003:7003/eureka,http://eureka7004:7004/eureka
  instance:
    #使用rancher扩容不能配置instance-id,否则会出问题
    #instance-id: SPRINGCLOUD-PROVIDER-PAYMENT-SERVICE-CLUSTER-NODE-PAYMENT8009-PROD #Eureka仪表盘中Instances currently registered with Eureka.Status显示的内容
    #使用rancher扩容不能配置iip-address,否则会出问题
    #ip-address: 192.168.0.4
    prefer-ip-address: true  #访问路径可以显示IP地址,点击Eureka仪表盘中Instances currently registered with Eureka.Status显示的内容地址栏是否显示IP地址
    lease-renewal-interval-in-seconds: 30 #Eureka客户端向服务端发送心跳的时间间隔,单位为秒(默认是30秒)
    lease-expiration-duration-in-seconds: 90 #Eureka服务端在收到最后一次心跳后等待时间上限,单位为秒(默认是90秒),超时将剔除服务

mybatis:
  mapperLocations: classpath:mapper/*.xml
  type-aliases-package: org.openatom.springcloud.entities    # 所有Entity别名类所在包


#配置文件修改说明-------------------------------------------------:开始
#注意:不同的部署环境需要修改的配置
#   1.${logback.path}  #修改日志存放位置,Linxu为/,Windows为\
#       修改原因: Linux和Windows目录结构不同
#配置文件修改说明-------------------------------------------------:结束

#自定义日志配置文件路径
logging:
  config: classpath:logback-custom.xml
  path: /logs #所有日志存放在位置,加上\方便Linux环境下配置
  level:
    root: info #全局日志输出级别

logback:
  log-name: ${spring.application.name}
  append: false #是否启用append(追加到已经存在日志文件尾部),true:重启项目会追加新日志到之前日志,false:重启项目会清空之前的日志
  immediate-flush: true #是否启用immediateFlush(立即刷新),true:重启项目自动追加,false:重启项目会情况之前的日志
  deploy-machine-ip: 192.168.0.4 #当前微服务所在部署机器ip

#logstash相关配置:开始
logstash:
  host: 192.168.0.4:5044 # logstash地址
  index: '@project.parent.artifactId@' # es中index名称
#logstash相关配置:结束

#actuator监控:开始
#通过下面的配置启用所有的监控端点,默认情况下,这些端点是禁用的;
management:
  endpoints:
    web:
      exposure:
        include: '*'
    enabled-by-default: true
  endpoint:
    health:
      show-details: always # 访问/actuator/health时,显示详细信息,而不是仅仅显示"status": "UP"
    # 日志文件路径:特别注意,此处无法配置日志文件路径,因为rancher会生成虚拟ip,这个虚拟ip是无法在这里获取的,
    #           但是虚拟ip是路径的一部分,所以这个路径无法拼接出来,所以这里无法配置日志文件路径
    #logfile:
    #  external-file:
#actuator监控:结束

logback-custom.xml
<?xml version="1.0" encoding="UTF-8"?>

<!--
    scan: 当此属性设置为true时,配置文件如果发生改变,将会被重新加载,默认值为true。
    scanPeriod: 设置监测配置文件是否有修改的时间间隔,如果没有给出时间单位,默认单位是毫秒。当scan为true时,此属性生效。默认的时间间隔为1分钟。
    debug: 当此属性设置为true时,将打印出logback内部日志信息,实时查看logback运行状态。默认值为false。
-->
<!-- 输出logback内部日志信息,每隔30s判断一下配置文件有没有更新,若更新,则重新加载 -->
<configuration scan="true" scanPeriod="30 seconds" debug="false">
    <!--从java代码中获取虚拟ip的值-->
    <!--获取当前微服务部署虚拟IP,如rancher为当前微服务分配的ip-->
    <define name="VIRTUAL_IP" class="org.openatom.springcloud.config.VirtualIpConfig"/>

    <!--从Spring容器中获取配置(Spring配置文件加载顺序:bootstrap.yml->logback.xml->application.yml)-->
    <!--获取当前微服务部署机器ip-->
    <springProperty name="MACHINE_IP" scope="context" source="logback.deploy-machine-ip"/>
    <!--应用名称-->
    <springProperty name="LOG_NAME" scope="context" source="logback.log-name"/>
    <!--是否启用append-->
    <springProperty name="IS_APPEND" scope="context" source="logback.append"/>
    <!--是否启用立即刷新-->
    <springProperty name="IS_IMMEDIATEFLUSH" scope="context" source="logback.immediate-flush"/>
    <springProperty name="LOG_PATH" scope="context" source="logging.path"/>
    <!--logstash地址-->
    <springProperty name="LOGSTASH_HOST" scope="context" source="logstash.host"/>
    <!--索引名称-->
    <springProperty name="INDEX_NAME" scope="context" source="logstash.index"/>


    <!-- name:变量的名称,可以随意起名,但建议名字要简明直译;value:变量的值;在配置文件中,我们可以用 ${} 的方式来使用,将变量引入到其他节点中去。-->
    <!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度 %msg:日志消息,%n是换行符-->
    <!--控制台日志输出预选样式-->
    <property name="CONSOLE_LOG_PATTERN_1" value="%red(%d{yyyy-MM-dd HH:mm:ss.SSS}) %green([%thread]) [machineIp:${MACHINE_IP} virtualIp:${VIRTUAL_IP}] [TraceId:%X{X-B3-TraceId:-} SpanId:%X{X-B3-SpanId:-} %highlight(%-5level) %boldMagenta(%logger{10}): %cyan(%msg%n)"/>
    <property name="CONSOLE_LOG_PATTERN_2" value="%yellow(%date{yyyy-MM-dd HH:mm:ss}) [machineIp:${MACHINE_IP} virtualIp:${VIRTUAL_IP}] [TraceId:%X{X-B3-TraceId:-} SpanId:%X{X-B3-SpanId:-} %highlight([%-5level]) %green(%logger) %msg%n"/>
    <property name="CONSOLE_LOG_PATTERN_3" value="%date{yyyy-MM-dd HH:mm:ss} [machineIp:${MACHINE_IP} virtualIp:${VIRTUAL_IP}] [TraceId:%X{X-B3-TraceId:-} SpanId:%X{X-B3-SpanId:-} Span-Export:%X{X-Span-Export:-}]  %green(%-5level) %boldMagenta(${PID:-}) -- [%+20thread] %cyan(%logger{20}) %line       : %msg%n"/>
    <!--文件中日志输出预选样式-->
    <property name="FILE_LOG_PATTERN_1" value="%d{yyyyMMdd:HH:mm:ss.SSS} [machineIp:${MACHINE_IP} virtualIp:${VIRTUAL_IP}] [TraceId:%X{X-B3-TraceId:-} SpanId:%X{X-B3-SpanId:-} [%thread] %-5level  %msg%n"/>

    <!--控制台日志输出格式-->
    <property name="CONSOLE_LOG_PATTERN" value="${CONSOLE_LOG_PATTERN_3}"/>
    <!--文件中日志输出格式-->
    <property name="FILE_LOG_PATTERN" value="${FILE_LOG_PATTERN_1}"/>
    <!--日志名称-->
    <!--定义默认日志输出级别-->
    <property name="LOG_OUTPUT_LEVEL" value="${LOG_LEVEL}" />
    <!--定义默认日志输出编码-->
    <property name="ENCODING" value="UTF-8" />

    <!-- 控制台输出:开始 -->
    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
        <!-- 用来设置日志的输入格式,使用“%+转换符”的方式,如果要输出”%”则必须使用”\”进行转义。-->
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <!-- 格式化输出:https://logback.qos.ch/manual/layouts.html
                 %d 表示日期,
                 %thread 表示线程名,
                 %level 日志级别从左显示5个字符宽度,
                 %t 线程名
                 %file:%line 文件名+行号,
                 %m 日志消息,%n是换行符
                 %X{traceId}:自定义设置的参数,后面会说。
            -->
            <pattern>${CONSOLE_LOG_PATTERN}</pattern>
            <charset>${ENCODING}</charset>
        </encoder>
    </appender>
    <!-- 控制台输出:结束 -->

    <!--输出到文件:开始-->
    <!-- 将项目本次运行INFO日志同步输出到文件,会自动清空文件中上一次的日志 -->
    <appender name="APPENDER-FILEAPPENDER-INFO" class="ch.qos.logback.core.FileAppender">
        <!-- 过滤器,只记录 info 级别以上的日志 -->
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <level>INFO</level>
        </filter>
        <!-- 写入的日志文件名,可以使相对目录也可以是绝对目录,如果上级目录不存在则自动创建 -->
        <file>${LOG_PATH}/${MACHINE_IP}/${VIRTUAL_IP}/${LOG_NAME}-info.log</file>
        <!-- 如果为true表示日志被追加到文件结尾,如果是false表示清空文件 -->
        <append>${IS_APPEND}</append>
        <!--立即刷新,设置成false可以提高日志吞吐量-->
        <immediateFlush>${IS_IMMEDIATEFLUSH}</immediateFlush>
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <pattern>${FILE_LOG_PATTERN}</pattern>
            <charset>${ENCODING}</charset>
        </encoder>
    </appender>

    <!-- 将项目本次运行INFO日志异步输出到文件,会自动清空文件中上一次的日志 -->
    <appender name="ASYNC-APPENDER-FILEAPPENDER-INFO" class="ch.qos.logback.classic.AsyncAppender">
        <appender-ref ref="APPENDER-FILEAPPENDER-INFO" />
        <!-- 设置异步阻塞队列的大小,为了不丢失日志建议设置的大一些,单机压测时100000是没问题的,应该不用担心OOM -->
        <queueSize>10000</queueSize>
        <!-- 设置丢弃DEBUG、TRACE、INFO日志的阀值,不丢失 -->
        <discardingThreshold>0</discardingThreshold>
        <!-- 设置队列入队时非阻塞,当队列满时会直接丢弃日志,但是对性能提升极大 -->
        <neverBlock>${IS_IMMEDIATEFLUSH}</neverBlock>
    </appender>

    <!-- 将项目本次运行DEBUG日志同步输出到文件,会自动清空文件中上一次的日志 -->
    <appender name="APPENDER-FILEAPPENDER-DEBUG" class="ch.qos.logback.core.FileAppender">
        <!-- 过滤器,只记录 info 级别以上的日志 -->
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <level>DEBUG</level>
        </filter>
        <!-- 写入的日志文件名,可以使相对目录也可以是绝对目录,如果上级目录不存在则自动创建 -->
        <file>${LOG_PATH}/${MACHINE_IP}/${VIRTUAL_IP}/${LOG_NAME}-debug.log</file>
        <!-- 如果为true表示日志被追加到文件结尾,如果是false表示清空文件 -->
        <append>${IS_APPEND}</append>
        <!--立即刷新,设置成false可以提高日志吞吐量-->
        <immediateFlush>true</immediateFlush>
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <pattern>${FILE_LOG_PATTERN}</pattern>
            <charset>${ENCODING}</charset>
        </encoder>
    </appender>

    <!-- 将项目本次运行DEBUG日志异步输出到文件,会自动清空文件中上一次的日志 -->
    <appender name="ASYNC-APPENDER-FILEAPPENDER-DEBUG" class="ch.qos.logback.classic.AsyncAppender">
        <appender-ref ref="APPENDER-FILEAPPENDER-DEBUG" />
        <!-- 设置异步阻塞队列的大小,为了不丢失日志建议设置的大一些,单机压测时100000是没问题的,应该不用担心OOM -->
        <queueSize>10000</queueSize>
        <!-- 设置丢弃DEBUG、TRACE、INFO日志的阀值,不丢失 -->
        <discardingThreshold>0</discardingThreshold>
        <!-- 设置队列入队时非阻塞,当队列满时会直接丢弃日志,但是对性能提升极大 -->
        <neverBlock>true</neverBlock>
    </appender>

    <!-- 将项目本次运行ERROR日志同步输出到文件,会自动清空文件中上一次的日志 -->
    <appender name="APPENDER-FILEAPPENDER-ERROR" class="ch.qos.logback.core.FileAppender">
        <!-- 过滤器,只记录 info 级别以上的日志 -->
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <level>DEBUG</level>
        </filter>
        <!-- 写入的日志文件名,可以使相对目录也可以是绝对目录,如果上级目录不存在则自动创建 -->
        <file>${LOG_PATH}/${MACHINE_IP}/${VIRTUAL_IP}/${LOG_NAME}-error.log</file>
        <!-- 如果为true表示日志被追加到文件结尾,如果是false表示清空文件 -->
        <append>${IS_APPEND}</append>
        <!--立即刷新,设置成false可以提高日志吞吐量-->
        <immediateFlush>${IS_IMMEDIATEFLUSH}</immediateFlush>
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <pattern>${FILE_LOG_PATTERN}</pattern>
            <charset>${ENCODING}</charset>
        </encoder>
    </appender>

    <!-- 将项目本次运行ERROR日志异步输出到文件,会自动清空文件中上一次的日志 -->
    <appender name="ASYNC-APPENDER-FILEAPPENDER-ERROR" class="ch.qos.logback.classic.AsyncAppender">
        <appender-ref ref="APPENDER-FILEAPPENDER-ERROR" />
        <!-- 设置异步阻塞队列的大小,为了不丢失日志建议设置的大一些,单机压测时100000是没问题的,应该不用担心OOM -->
        <queueSize>10000</queueSize>
        <!-- 设置丢弃DEBUG、TRACE、INFO日志的阀值,不丢失 -->
        <discardingThreshold>0</discardingThreshold>
        <!-- 设置队列入队时非阻塞,当队列满时会直接丢弃日志,但是对性能提升极大 -->
        <neverBlock>true</neverBlock>
    </appender>
    <!--输出到文件:结束-->


    <!--滚动输出到文件(按照天保存):开始-->
    <!-- 将项目本次运行INFO日志同步输出到文件,按照每天生成日志文件,会自动拼接上一次日志 -->
    <appender name="APPENDER-ROLLINGFILEAPPENDER-INFO" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <!-- 过滤器,只记录 info 级别以上的日志 -->
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <level>INFO</level>
        </filter>
        <!--立即刷新,设置成false可以提高日志吞吐量-->
        <immediateFlush>false</immediateFlush>
        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
            <!-- 日志文件输出的文件名:
                %d:可以包含一个Java.text.SimpleDateFormat指定的时间格式
                %i:自增数字
            -->
            <fileNamePattern>${LOG_PATH}/${MACHINE_IP}/${VIRTUAL_IP}/HISTORY/${LOG_NAME}-info-%d{yyyy-MM-dd}-index%i.log</fileNamePattern>
            <!-- 日志文件保存历史数量:控制保留的归档文件的最大数量,如果超出数量就删除旧文件 -->
            <maxHistory>10</maxHistory>
            <!-- 文件大小超过100MB归档 -->
            <maxFileSize>20MB</maxFileSize>
        </rollingPolicy>
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <pattern>${FILE_LOG_PATTERN}</pattern>
            <charset>${ENCODING}</charset>
        </encoder>
    </appender>

    <!-- 将项目本次运行INFO日志异步输出到文件,按照每天生成日志文件,会自动拼接上一次日志 -->
    <appender name="ASYNC-APPENDER-ROLLINGFILEAPPENDER-INFO" class="ch.qos.logback.classic.AsyncAppender">
        <appender-ref ref="APPENDER-ROLLINGFILEAPPENDER-INFO" />
        <!-- 设置异步阻塞队列的大小,为了不丢失日志建议设置的大一些,单机压测时100000是没问题的,应该不用担心OOM -->
        <queueSize>10000</queueSize>
        <!-- 设置丢弃DEBUG、TRACE、INFO日志的阀值,不丢失 -->
        <discardingThreshold>0</discardingThreshold>
        <!-- 设置队列入队时非阻塞,当队列满时会直接丢弃日志,但是对性能提升极大 -->
        <neverBlock>true</neverBlock>
    </appender>

    <!-- 将项目本次运行DEBUG日志同步输出到文件,按照每天生成日志文件,会自动拼接上一次日志 -->
    <appender name="APPENDER-ROLLINGFILEAPPENDER-DEBUG" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <!-- 过滤器,只记录 info 级别以上的日志 -->
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <level>DEBUG</level>
        </filter>
        <!--立即刷新,设置成false可以提高日志吞吐量-->
        <immediateFlush>false</immediateFlush>
        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
            <!-- 日志文件输出的文件名:
                %d:可以包含一个Java.text.SimpleDateFormat指定的时间格式
                %i:自增数字
            -->
            <fileNamePattern>${LOG_PATH}/${MACHINE_IP}/${VIRTUAL_IP}/HISTORY/${LOG_NAME}-debug-%d{yyyy-MM-dd}-index%i.log</fileNamePattern>
            <!-- 日志文件保存历史数量:控制保留的归档文件的最大数量,如果超出数量就删除旧文件 -->
            <maxHistory>10</maxHistory>
            <!-- 文件大小超过100MB归档 -->
            <maxFileSize>20MB</maxFileSize>
        </rollingPolicy>
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <pattern>${FILE_LOG_PATTERN}</pattern>
            <charset>${ENCODING}</charset>
        </encoder>
    </appender>

    <!-- 将项目本次运行DEBUG日志异步输出到文件,按照每天生成日志文件,会自动拼接上一次日志 -->
    <appender name="ASYNC-APPENDER-ROLLINGFILEAPPENDER-DEBUG" class="ch.qos.logback.classic.AsyncAppender">
        <appender-ref ref="APPENDER-ROLLINGFILEAPPENDER-DEBUG" />
        <!-- 设置异步阻塞队列的大小,为了不丢失日志建议设置的大一些,单机压测时100000是没问题的,应该不用担心OOM -->
        <queueSize>10000</queueSize>
        <!-- 设置丢弃DEBUG、TRACE、INFO日志的阀值,不丢失 -->
        <discardingThreshold>0</discardingThreshold>
        <!-- 设置队列入队时非阻塞,当队列满时会直接丢弃日志,但是对性能提升极大 -->
        <neverBlock>true</neverBlock>
    </appender>

    <!-- 将项目本次运行ERROR日志同步输出到文件,按照每天生成日志文件,会自动拼接上一次日志 -->
    <appender name="APPENDER-ROLLINGFILEAPPENDER-ERROR" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <!-- 过滤器,只记录error级别的日志 -->
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>ERROR</level>
            <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>
        <!--立即刷新,设置成false可以提高日志吞吐量-->
        <immediateFlush>false</immediateFlush>
        <!-- 每天生成一个日志文件,保存30天的日志文件 -->
        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
            <!-- 日志文件输出的文件名:按天回滚 daily -->
            <fileNamePattern>${LOG_PATH}/${MACHINE_IP}/${VIRTUAL_IP}/HISTORY/${LOG_NAME}-error-%d{yyyy-MM-dd}-index%i.log</fileNamePattern>
            <!-- 日志文件保留天数 -->
            <maxHistory>10</maxHistory>
            <!-- 文件大小超过100MB归档 -->
            <maxFileSize>20MB</maxFileSize>
        </rollingPolicy>
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <pattern>${FILE_LOG_PATTERN}</pattern>
            <charset>utf8</charset>
        </encoder>
    </appender>

    <appender name="ASYNC-APPENDER-ROLLINGFILEAPPENDER-ERROR" class="ch.qos.logback.classic.AsyncAppender">
        <appender-ref ref="APPENDER-ROLLINGFILEAPPENDER-ERROR" />
        <!-- 设置异步阻塞队列的大小,为了不丢失日志建议设置的大一些,单机压测时100000是没问题的,应该不用担心OOM -->
        <queueSize>10000</queueSize>
        <!-- 设置丢弃DEBUG、TRACE、INFO日志的阀值,不丢失 -->
        <discardingThreshold>0</discardingThreshold>
        <!-- 设置队列入队时非阻塞,当队列满时会直接丢弃日志,但是对性能提升极大 -->
        <neverBlock>true</neverBlock>
    </appender>
    <!--滚动输出到文件(按照天保存):结束-->

    <!--输出到LOGSTASH:开始-->
    <!-- 将项目本次运行ERROR日志同步输出到文件,按照每天生成日志文件,会自动拼接上一次日志 -->
    <appender name="APPENDER-LOGSTASH" class="net.logstash.logback.appender.LogstashTcpSocketAppender">
        <!--  logstash服务器地址-->
        <destination>${LOGSTASH_HOST}</destination>
        <encoder class="net.logstash.logback.encoder.LoggingEventCompositeJsonEncoder">
            <providers>
                <pattern>
                    <pattern>
                        {
                        "appName":"${INDEX_NAME}",
                        "machineIp":"${MACHINE_IP}",
                        "virtualIp":"${VIRTUAL_IP}",
                        "serviceName":"${LOG_NAME}",
                        "timestamp": "%date{\"yyyy-MM-dd'T'HH:mm:ss,SSSZ\"}",
                        "logLevel":"%level",
                        "message":"%msg%n",
                        "traceId": "%X{X-B3-TraceId:-}",
                        "spanId": "%X{X-B3-SpanId:-}",
                        "spanExport": "%X{X-Span-Export:-}"
                        }
                    </pattern>
                </pattern>
            </providers>
        </encoder>
    </appender>
    <appender name="ASYNC-APPENDER-LOGSTASH" class="ch.qos.logback.classic.AsyncAppender">
        <appender-ref ref="APPENDER-LOGSTASH" />
        <!-- 设置异步阻塞队列的大小,为了不丢失日志建议设置的大一些,单机压测时100000是没问题的,应该不用担心OOM -->
        <queueSize>10000</queueSize>
        <!-- 设置丢弃DEBUG、TRACE、INFO日志的阀值,不丢失 -->
        <discardingThreshold>0</discardingThreshold>
        <!-- 设置队列入队时非阻塞,当队列满时会直接丢弃日志,但是对性能提升极大 -->
        <neverBlock>true</neverBlock>
    </appender>
    <!--输出到logstash:结束-->

    <!--
        开发环境日志级别为DEBUG
        level:用来设置打印级别
        五个常用打印级别从低至高依次为TRACE、DEBUG、INFO、WARN、ERROR
    -->
    <springProfile name="dev">
        <root>
            <!--输出到控制台-->
            <appender-ref ref="STDOUT"/>
            <!--异步非滚动输出到文件-->
            <appender-ref ref="ASYNC-APPENDER-FILEAPPENDER-INFO"/>
            <appender-ref ref="ASYNC-APPENDER-FILEAPPENDER-DEBUG"/>
            <appender-ref ref="ASYNC-APPENDER-FILEAPPENDER-ERROR"/>
            <!--异步滚动输出到文件:dev环境不开启-->
<!--            <appender-ref ref="ASYNC-APPENDER-ROLLINGFILEAPPENDER-INFO"/>-->
<!--            <appender-ref ref="ASYNC-APPENDER-ROLLINGFILEAPPENDER-DEBUG"/>-->
<!--            <appender-ref ref="ASYNC-APPENDER-ROLLINGFILEAPPENDER-ERROR"/>-->
            <!--异步滚动输出到logstash-->
            <appender-ref ref="ASYNC-APPENDER-LOGSTASH"/>
        </root>
    </springProfile>

    <!-- 测试环境日志级别为INFO -->
    <springProfile name="test">
        <root>
            <!--输出到控制台-->
            <appender-ref ref="STDOUT"/>
            <!--异步非滚动输出到文件-->
            <appender-ref ref="ASYNC-APPENDER-FILEAPPENDER-INFO"/>
            <appender-ref ref="ASYNC-APPENDER-FILEAPPENDER-DEBUG"/>
            <appender-ref ref="ASYNC-APPENDER-FILEAPPENDER-ERROR"/>
            <!--异步滚动输出到文件:test环境不开启-->
<!--            <appender-ref ref="ASYNC-APPENDER-ROLLINGFILEAPPENDER-INFO"/>-->
<!--            <appender-ref ref="ASYNC-APPENDER-ROLLINGFILEAPPENDER-DEBUG"/>-->
<!--            <appender-ref ref="ASYNC-APPENDER-ROLLINGFILEAPPENDER-ERROR"/>-->
            <!--异步滚动输出到logstash-->
            <appender-ref ref="ASYNC-APPENDER-LOGSTASH"/>
        </root>
    </springProfile>

    <!-- 生产环境日志级别为INFO -->
    <springProfile name="prod">
        <root>
            <!--输出到控制台-->
            <appender-ref ref="STDOUT"/>
            <!--异步非滚动输出到文件-->
            <appender-ref ref="ASYNC-APPENDER-FILEAPPENDER-INFO"/>
            <appender-ref ref="ASYNC-APPENDER-FILEAPPENDER-DEBUG"/>
            <appender-ref ref="ASYNC-APPENDER-FILEAPPENDER-ERROR"/>
            <!--异步滚动输出到文件-->
            <appender-ref ref="ASYNC-APPENDER-ROLLINGFILEAPPENDER-INFO"/>
            <appender-ref ref="ASYNC-APPENDER-ROLLINGFILEAPPENDER-DEBUG"/>
            <appender-ref ref="ASYNC-APPENDER-ROLLINGFILEAPPENDER-ERROR"/>
            <!--异步滚动输出到logstash-->
            <appender-ref ref="ASYNC-APPENDER-LOGSTASH"/>
        </root>
    </springProfile>

    <!-- rancher环境日志级别为INFO -->
    <springProfile name="rancher">
        <root>
            <!--输出到控制台-->
            <appender-ref ref="STDOUT"/>
            <!--异步非滚动输出到文件-->
            <appender-ref ref="ASYNC-APPENDER-FILEAPPENDER-INFO"/>
            <appender-ref ref="ASYNC-APPENDER-FILEAPPENDER-DEBUG"/>
            <appender-ref ref="ASYNC-APPENDER-FILEAPPENDER-ERROR"/>
            <!--异步滚动输出到文件-->
            <appender-ref ref="ASYNC-APPENDER-ROLLINGFILEAPPENDER-INFO"/>
            <appender-ref ref="ASYNC-APPENDER-ROLLINGFILEAPPENDER-DEBUG"/>
            <appender-ref ref="ASYNC-APPENDER-ROLLINGFILEAPPENDER-ERROR"/>
            <!--异步滚动输出到logstash-->
            <appender-ref ref="ASYNC-APPENDER-LOGSTASH"/>
        </root>
    </springProfile>
</configuration>

PaymentMapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >

<mapper namespace="org.openatom.springcloud.dao.PaymentDao">

    <!--第一种写法:parameterType不写全路径-->
    <insert id="create" parameterType="Payment" useGeneratedKeys="true" keyProperty="id">
        insert into payment(serial)  values(#{serial});
    </insert>

    <resultMap id="BaseResultMap" type="Payment">
        <id column="id" property="id" jdbcType="BIGINT"/>
        <id column="serial" property="serial" jdbcType="VARCHAR"/>
    </resultMap>
    <select id="getPaymentById" parameterType="Long" resultMap="BaseResultMap">
        select * from payment where id=#{id};
    </select>

    <!--第二种写法:parameterType的写法与第一种有区别-->
    <!--
    <insert id="create" parameterType="org.openatom.springcloud.entities.Payment" useGeneratedKeys="true" keyProperty="id">
        insert into payment(serial)  values(#{serial});
    </insert>

    <resultMap id="BaseResultMap" type="org.openatom.springcloud.entities.Payment">
        <id column="id" property="id" jdbcType="BIGINT"/>
        <id column="serial" property="serial" jdbcType="VARCHAR"/>
    </resultMap>
    <select id="getPaymentById" parameterType="Long" resultMap="BaseResultMap">
        select * from payment where id=#{id};
    </select>
    -->
</mapper>



test环境配置文件
application.yml
#设置spring项目运行的环境
spring:
  profiles:
    active: '@profile.active@'


application-test.yml
server:
  port: 8009 #访问端口
spring:
  application:
    name: SPRINGCLOUD-BASIC-SAMPLE-PROVIDER-PAYMENT-SERVICE-CLUSTER-TEST  #注意:服务名不要出现_
  devtools: #热部署开关
    restart:
      enabled: true
  # 将Client作为服务注册到SpringBootAdmin Server端,通过Server来监听项目的运行情况
  boot:
    admin:
      client:
        url: http://localhost:${server.port}
  logging:
    level: info
  datasource:
    type: com.alibaba.druid.pool.DruidDataSource            # 当前数据源操作类型
    driver-class-name: com.mysql.cj.jdbc.Driver              # mysql驱动包
    url: jdbc:mysql://192.168.0.5:3306/payment?useUnicode=true&characterEncoding=utf-8&useSSL=false
    username: root
    password: Mysql123456_

eureka:
  client:
    register-with-eureka: true  #表示是否将自己注册进EurekaServer默认为true。
    fetchRegistry: true  #是否从EurekaServer抓取已有的注册信息,默认为true。单节点无所谓,集群必须设置为true才能配合ribbon使用负载均衡
    service-url:
      #单机版
      defaultZone: http://localhost:7005/eureka
      #集群版
      #defaultZone: http://eureka7002:7002/eureka,http://eureka7003:7003/eureka,http://eureka7004:7004/eureka
  instance:
    instance-id: SPRINGCLOUD-PROVIDER-PAYMENT-SERVICE-CLUSTER-NODE-PAYMENT8009-TEST #Eureka仪表盘中Instances currently registered with Eureka.Status显示的内容
    #当前微服务所在部署机器ip
    ip-address: localhost
    prefer-ip-address: true  #访问路径可以显示IP地址,点击Eureka仪表盘中Instances currently registered with Eureka.Status显示的内容地址栏是否显示IP地址
    lease-renewal-interval-in-seconds: 30 #Eureka客户端向服务端发送心跳的时间间隔,单位为秒(默认是30秒)
    lease-expiration-duration-in-seconds: 90 #Eureka服务端在收到最后一次心跳后等待时间上限,单位为秒(默认是90秒),超时将剔除服务

mybatis:
  mapperLocations: classpath:mapper/*.xml
  type-aliases-package: org.openatom.springcloud.entities    # 所有Entity别名类所在包


#配置文件修改说明-------------------------------------------------:开始
#注意:不同的部署环境需要修改的配置
#   1.${logback.path}  #修改日志存放位置,Linxu为/,Windows为\
#       修改原因: Linux和Windows目录结构不同
#配置文件修改说明-------------------------------------------------:结束

#自定义日志配置文件路径
logging:
  config: classpath:logback-custom.xml
  path: D:\repository\workspace\IDEA\PERSONAL\springcloud-eureka\log\ #所有日志存放在位置,加上\方便Linux环境下配置
  level:
    root: info #全局日志输出级别

logback:
  log-name: ${spring.application.name}
  append: false #是否启用append(追加到已经存在日志文件尾部),true:重启项目会追加新日志到之前日志,false:重启项目会清空之前的日志
  immediate-flush: true #是否启用immediateFlush(立即刷新),true:重启项目自动追加,false:重启项目会情况之前的日志
  deploy-machine-ip: ${eureka.instance.ip-address} #当前微服务所在部署机器ip

#logstash相关配置:开始
logstash:
  host: 192.168.0.4:5044 # logstash地址
  index: '@project.parent.artifactId@' # es中index名称
#logstash相关配置:结束

#actuator监控:开始
#通过下面的配置启用所有的监控端点,默认情况下,这些端点是禁用的;
management:
  endpoints:
    web:
      exposure:
        include: '*'
    enabled-by-default: true
  endpoint:
    health:
      show-details: always # 访问/actuator/health时,显示详细信息,而不是仅仅显示"status": "UP"
    # 日志文件路径:特别注意,此处无法配置日志文件路径,因为rancher会生成虚拟ip,这个虚拟ip是无法在这里获取的,
    #           但是虚拟ip是路径的一部分,所以这个路径无法拼接出来,所以这里无法配置日志文件路径
    #logfile:
    #  external-file:
#actuator监控:结束

logback-custom.xml
<?xml version="1.0" encoding="UTF-8"?>

<!--
    scan: 当此属性设置为true时,配置文件如果发生改变,将会被重新加载,默认值为true。
    scanPeriod: 设置监测配置文件是否有修改的时间间隔,如果没有给出时间单位,默认单位是毫秒。当scan为true时,此属性生效。默认的时间间隔为1分钟。
    debug: 当此属性设置为true时,将打印出logback内部日志信息,实时查看logback运行状态。默认值为false。
-->
<!-- 输出logback内部日志信息,每隔30s判断一下配置文件有没有更新,若更新,则重新加载 -->
<configuration scan="true" scanPeriod="30 seconds" debug="false">
    <!--从java代码中获取虚拟ip的值-->
    <!--获取当前微服务部署虚拟IP,如rancher为当前微服务分配的ip-->
    <define name="VIRTUAL_IP" class="org.openatom.springcloud.config.VirtualIpConfig"/>

    <!--从Spring容器中获取配置(Spring配置文件加载顺序:bootstrap.yml->logback.xml->application.yml)-->
    <!--获取当前微服务部署机器ip-->
    <springProperty name="MACHINE_IP" scope="context" source="logback.deploy-machine-ip"/>
    <!--应用名称-->
    <springProperty name="LOG_NAME" scope="context" source="logback.log-name"/>
    <!--是否启用append-->
    <springProperty name="IS_APPEND" scope="context" source="logback.append"/>
    <!--是否启用立即刷新-->
    <springProperty name="IS_IMMEDIATEFLUSH" scope="context" source="logback.immediate-flush"/>
    <springProperty name="LOG_PATH" scope="context" source="logging.path"/>
    <!--logstash地址-->
    <springProperty name="LOGSTASH_HOST" scope="context" source="logstash.host"/>
    <!--索引名称-->
    <springProperty name="INDEX_NAME" scope="context" source="logstash.index"/>


    <!-- name:变量的名称,可以随意起名,但建议名字要简明直译;value:变量的值;在配置文件中,我们可以用 ${} 的方式来使用,将变量引入到其他节点中去。-->
    <!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度 %msg:日志消息,%n是换行符-->
    <!--控制台日志输出预选样式-->
    <property name="CONSOLE_LOG_PATTERN_1" value="%red(%d{yyyy-MM-dd HH:mm:ss.SSS}) %green([%thread]) [machineIp:${MACHINE_IP} virtualIp:${VIRTUAL_IP}] [TraceId:%X{X-B3-TraceId:-} SpanId:%X{X-B3-SpanId:-} %highlight(%-5level) %boldMagenta(%logger{10}): %cyan(%msg%n)"/>
    <property name="CONSOLE_LOG_PATTERN_2" value="%yellow(%date{yyyy-MM-dd HH:mm:ss}) [machineIp:${MACHINE_IP} virtualIp:${VIRTUAL_IP}] [TraceId:%X{X-B3-TraceId:-} SpanId:%X{X-B3-SpanId:-} %highlight([%-5level]) %green(%logger) %msg%n"/>
    <property name="CONSOLE_LOG_PATTERN_3" value="%date{yyyy-MM-dd HH:mm:ss} [machineIp:${MACHINE_IP} virtualIp:${VIRTUAL_IP}] [TraceId:%X{X-B3-TraceId:-} SpanId:%X{X-B3-SpanId:-} Span-Export:%X{X-Span-Export:-}]  %green(%-5level) %boldMagenta(${PID:-}) -- [%+20thread] %cyan(%logger{20}) %line       : %msg%n"/>
    <!--文件中日志输出预选样式-->
    <property name="FILE_LOG_PATTERN_1" value="%d{yyyyMMdd:HH:mm:ss.SSS} [machineIp:${MACHINE_IP} virtualIp:${VIRTUAL_IP}] [TraceId:%X{X-B3-TraceId:-} SpanId:%X{X-B3-SpanId:-} [%thread] %-5level  %msg%n"/>

    <!--控制台日志输出格式-->
    <property name="CONSOLE_LOG_PATTERN" value="${CONSOLE_LOG_PATTERN_3}"/>
    <!--文件中日志输出格式-->
    <property name="FILE_LOG_PATTERN" value="${FILE_LOG_PATTERN_1}"/>
    <!--日志名称-->
    <!--定义默认日志输出级别-->
    <property name="LOG_OUTPUT_LEVEL" value="${LOG_LEVEL}" />
    <!--定义默认日志输出编码-->
    <property name="ENCODING" value="UTF-8" />

    <!-- 控制台输出:开始 -->
    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
        <!-- 用来设置日志的输入格式,使用“%+转换符”的方式,如果要输出”%”则必须使用”\”进行转义。-->
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <!-- 格式化输出:https://logback.qos.ch/manual/layouts.html
                 %d 表示日期,
                 %thread 表示线程名,
                 %level 日志级别从左显示5个字符宽度,
                 %t 线程名
                 %file:%line 文件名+行号,
                 %m 日志消息,%n是换行符
                 %X{traceId}:自定义设置的参数,后面会说。
            -->
            <pattern>${CONSOLE_LOG_PATTERN}</pattern>
            <charset>${ENCODING}</charset>
        </encoder>
    </appender>
    <!-- 控制台输出:结束 -->

    <!--输出到文件:开始-->
    <!-- 将项目本次运行INFO日志同步输出到文件,会自动清空文件中上一次的日志 -->
    <appender name="APPENDER-FILEAPPENDER-INFO" class="ch.qos.logback.core.FileAppender">
        <!-- 过滤器,只记录 info 级别以上的日志 -->
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <level>INFO</level>
        </filter>
        <!-- 写入的日志文件名,可以使相对目录也可以是绝对目录,如果上级目录不存在则自动创建 -->
        <file>${LOG_PATH}/${MACHINE_IP}/${VIRTUAL_IP}/${LOG_NAME}-info.log</file>
        <!-- 如果为true表示日志被追加到文件结尾,如果是false表示清空文件 -->
        <append>${IS_APPEND}</append>
        <!--立即刷新,设置成false可以提高日志吞吐量-->
        <immediateFlush>${IS_IMMEDIATEFLUSH}</immediateFlush>
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <pattern>${FILE_LOG_PATTERN}</pattern>
            <charset>${ENCODING}</charset>
        </encoder>
    </appender>

    <!-- 将项目本次运行INFO日志异步输出到文件,会自动清空文件中上一次的日志 -->
    <appender name="ASYNC-APPENDER-FILEAPPENDER-INFO" class="ch.qos.logback.classic.AsyncAppender">
        <appender-ref ref="APPENDER-FILEAPPENDER-INFO" />
        <!-- 设置异步阻塞队列的大小,为了不丢失日志建议设置的大一些,单机压测时100000是没问题的,应该不用担心OOM -->
        <queueSize>10000</queueSize>
        <!-- 设置丢弃DEBUG、TRACE、INFO日志的阀值,不丢失 -->
        <discardingThreshold>0</discardingThreshold>
        <!-- 设置队列入队时非阻塞,当队列满时会直接丢弃日志,但是对性能提升极大 -->
        <neverBlock>${IS_IMMEDIATEFLUSH}</neverBlock>
    </appender>

    <!-- 将项目本次运行DEBUG日志同步输出到文件,会自动清空文件中上一次的日志 -->
    <appender name="APPENDER-FILEAPPENDER-DEBUG" class="ch.qos.logback.core.FileAppender">
        <!-- 过滤器,只记录 info 级别以上的日志 -->
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <level>DEBUG</level>
        </filter>
        <!-- 写入的日志文件名,可以使相对目录也可以是绝对目录,如果上级目录不存在则自动创建 -->
        <file>${LOG_PATH}/${MACHINE_IP}/${VIRTUAL_IP}/${LOG_NAME}-debug.log</file>
        <!-- 如果为true表示日志被追加到文件结尾,如果是false表示清空文件 -->
        <append>${IS_APPEND}</append>
        <!--立即刷新,设置成false可以提高日志吞吐量-->
        <immediateFlush>true</immediateFlush>
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <pattern>${FILE_LOG_PATTERN}</pattern>
            <charset>${ENCODING}</charset>
        </encoder>
    </appender>

    <!-- 将项目本次运行DEBUG日志异步输出到文件,会自动清空文件中上一次的日志 -->
    <appender name="ASYNC-APPENDER-FILEAPPENDER-DEBUG" class="ch.qos.logback.classic.AsyncAppender">
        <appender-ref ref="APPENDER-FILEAPPENDER-DEBUG" />
        <!-- 设置异步阻塞队列的大小,为了不丢失日志建议设置的大一些,单机压测时100000是没问题的,应该不用担心OOM -->
        <queueSize>10000</queueSize>
        <!-- 设置丢弃DEBUG、TRACE、INFO日志的阀值,不丢失 -->
        <discardingThreshold>0</discardingThreshold>
        <!-- 设置队列入队时非阻塞,当队列满时会直接丢弃日志,但是对性能提升极大 -->
        <neverBlock>true</neverBlock>
    </appender>

    <!-- 将项目本次运行ERROR日志同步输出到文件,会自动清空文件中上一次的日志 -->
    <appender name="APPENDER-FILEAPPENDER-ERROR" class="ch.qos.logback.core.FileAppender">
        <!-- 过滤器,只记录 info 级别以上的日志 -->
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <level>DEBUG</level>
        </filter>
        <!-- 写入的日志文件名,可以使相对目录也可以是绝对目录,如果上级目录不存在则自动创建 -->
        <file>${LOG_PATH}/${MACHINE_IP}/${VIRTUAL_IP}/${LOG_NAME}-error.log</file>
        <!-- 如果为true表示日志被追加到文件结尾,如果是false表示清空文件 -->
        <append>${IS_APPEND}</append>
        <!--立即刷新,设置成false可以提高日志吞吐量-->
        <immediateFlush>${IS_IMMEDIATEFLUSH}</immediateFlush>
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <pattern>${FILE_LOG_PATTERN}</pattern>
            <charset>${ENCODING}</charset>
        </encoder>
    </appender>

    <!-- 将项目本次运行ERROR日志异步输出到文件,会自动清空文件中上一次的日志 -->
    <appender name="ASYNC-APPENDER-FILEAPPENDER-ERROR" class="ch.qos.logback.classic.AsyncAppender">
        <appender-ref ref="APPENDER-FILEAPPENDER-ERROR" />
        <!-- 设置异步阻塞队列的大小,为了不丢失日志建议设置的大一些,单机压测时100000是没问题的,应该不用担心OOM -->
        <queueSize>10000</queueSize>
        <!-- 设置丢弃DEBUG、TRACE、INFO日志的阀值,不丢失 -->
        <discardingThreshold>0</discardingThreshold>
        <!-- 设置队列入队时非阻塞,当队列满时会直接丢弃日志,但是对性能提升极大 -->
        <neverBlock>true</neverBlock>
    </appender>
    <!--输出到文件:结束-->


    <!--滚动输出到文件(按照天保存):开始-->
    <!-- 将项目本次运行INFO日志同步输出到文件,按照每天生成日志文件,会自动拼接上一次日志 -->
    <appender name="APPENDER-ROLLINGFILEAPPENDER-INFO" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <!-- 过滤器,只记录 info 级别以上的日志 -->
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <level>INFO</level>
        </filter>
        <!--立即刷新,设置成false可以提高日志吞吐量-->
        <immediateFlush>false</immediateFlush>
        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
            <!-- 日志文件输出的文件名:
                %d:可以包含一个Java.text.SimpleDateFormat指定的时间格式
                %i:自增数字
            -->
            <fileNamePattern>${LOG_PATH}/${MACHINE_IP}/${VIRTUAL_IP}/HISTORY/${LOG_NAME}-info-%d{yyyy-MM-dd}-index%i.log</fileNamePattern>
            <!-- 日志文件保存历史数量:控制保留的归档文件的最大数量,如果超出数量就删除旧文件 -->
            <maxHistory>10</maxHistory>
            <!-- 文件大小超过100MB归档 -->
            <maxFileSize>20MB</maxFileSize>
        </rollingPolicy>
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <pattern>${FILE_LOG_PATTERN}</pattern>
            <charset>${ENCODING}</charset>
        </encoder>
    </appender>

    <!-- 将项目本次运行INFO日志异步输出到文件,按照每天生成日志文件,会自动拼接上一次日志 -->
    <appender name="ASYNC-APPENDER-ROLLINGFILEAPPENDER-INFO" class="ch.qos.logback.classic.AsyncAppender">
        <appender-ref ref="APPENDER-ROLLINGFILEAPPENDER-INFO" />
        <!-- 设置异步阻塞队列的大小,为了不丢失日志建议设置的大一些,单机压测时100000是没问题的,应该不用担心OOM -->
        <queueSize>10000</queueSize>
        <!-- 设置丢弃DEBUG、TRACE、INFO日志的阀值,不丢失 -->
        <discardingThreshold>0</discardingThreshold>
        <!-- 设置队列入队时非阻塞,当队列满时会直接丢弃日志,但是对性能提升极大 -->
        <neverBlock>true</neverBlock>
    </appender>

    <!-- 将项目本次运行DEBUG日志同步输出到文件,按照每天生成日志文件,会自动拼接上一次日志 -->
    <appender name="APPENDER-ROLLINGFILEAPPENDER-DEBUG" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <!-- 过滤器,只记录 info 级别以上的日志 -->
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <level>DEBUG</level>
        </filter>
        <!--立即刷新,设置成false可以提高日志吞吐量-->
        <immediateFlush>false</immediateFlush>
        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
            <!-- 日志文件输出的文件名:
                %d:可以包含一个Java.text.SimpleDateFormat指定的时间格式
                %i:自增数字
            -->
            <fileNamePattern>${LOG_PATH}/${MACHINE_IP}/${VIRTUAL_IP}/HISTORY/${LOG_NAME}-debug-%d{yyyy-MM-dd}-index%i.log</fileNamePattern>
            <!-- 日志文件保存历史数量:控制保留的归档文件的最大数量,如果超出数量就删除旧文件 -->
            <maxHistory>10</maxHistory>
            <!-- 文件大小超过100MB归档 -->
            <maxFileSize>20MB</maxFileSize>
        </rollingPolicy>
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <pattern>${FILE_LOG_PATTERN}</pattern>
            <charset>${ENCODING}</charset>
        </encoder>
    </appender>

    <!-- 将项目本次运行DEBUG日志异步输出到文件,按照每天生成日志文件,会自动拼接上一次日志 -->
    <appender name="ASYNC-APPENDER-ROLLINGFILEAPPENDER-DEBUG" class="ch.qos.logback.classic.AsyncAppender">
        <appender-ref ref="APPENDER-ROLLINGFILEAPPENDER-DEBUG" />
        <!-- 设置异步阻塞队列的大小,为了不丢失日志建议设置的大一些,单机压测时100000是没问题的,应该不用担心OOM -->
        <queueSize>10000</queueSize>
        <!-- 设置丢弃DEBUG、TRACE、INFO日志的阀值,不丢失 -->
        <discardingThreshold>0</discardingThreshold>
        <!-- 设置队列入队时非阻塞,当队列满时会直接丢弃日志,但是对性能提升极大 -->
        <neverBlock>true</neverBlock>
    </appender>

    <!-- 将项目本次运行ERROR日志同步输出到文件,按照每天生成日志文件,会自动拼接上一次日志 -->
    <appender name="APPENDER-ROLLINGFILEAPPENDER-ERROR" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <!-- 过滤器,只记录error级别的日志 -->
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>ERROR</level>
            <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>
        <!--立即刷新,设置成false可以提高日志吞吐量-->
        <immediateFlush>false</immediateFlush>
        <!-- 每天生成一个日志文件,保存30天的日志文件 -->
        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
            <!-- 日志文件输出的文件名:按天回滚 daily -->
            <fileNamePattern>${LOG_PATH}/${MACHINE_IP}/${VIRTUAL_IP}/HISTORY/${LOG_NAME}-error-%d{yyyy-MM-dd}-index%i.log</fileNamePattern>
            <!-- 日志文件保留天数 -->
            <maxHistory>10</maxHistory>
            <!-- 文件大小超过100MB归档 -->
            <maxFileSize>20MB</maxFileSize>
        </rollingPolicy>
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <pattern>${FILE_LOG_PATTERN}</pattern>
            <charset>utf8</charset>
        </encoder>
    </appender>

    <appender name="ASYNC-APPENDER-ROLLINGFILEAPPENDER-ERROR" class="ch.qos.logback.classic.AsyncAppender">
        <appender-ref ref="APPENDER-ROLLINGFILEAPPENDER-ERROR" />
        <!-- 设置异步阻塞队列的大小,为了不丢失日志建议设置的大一些,单机压测时100000是没问题的,应该不用担心OOM -->
        <queueSize>10000</queueSize>
        <!-- 设置丢弃DEBUG、TRACE、INFO日志的阀值,不丢失 -->
        <discardingThreshold>0</discardingThreshold>
        <!-- 设置队列入队时非阻塞,当队列满时会直接丢弃日志,但是对性能提升极大 -->
        <neverBlock>true</neverBlock>
    </appender>
    <!--滚动输出到文件(按照天保存):结束-->

    <!--输出到LOGSTASH:开始-->
    <!-- 将项目本次运行ERROR日志同步输出到文件,按照每天生成日志文件,会自动拼接上一次日志 -->
    <appender name="APPENDER-LOGSTASH" class="net.logstash.logback.appender.LogstashTcpSocketAppender">
        <!--  logstash服务器地址-->
        <destination>${LOGSTASH_HOST}</destination>
        <encoder class="net.logstash.logback.encoder.LoggingEventCompositeJsonEncoder">
            <providers>
                <pattern>
                    <pattern>
                        {
                        "appName":"${INDEX_NAME}",
                        "machineIp":"${MACHINE_IP}",
                        "virtualIp":"${VIRTUAL_IP}",
                        "serviceName":"${LOG_NAME}",
                        "timestamp": "%date{\"yyyy-MM-dd'T'HH:mm:ss,SSSZ\"}",
                        "logLevel":"%level",
                        "message":"%msg%n",
                        "traceId": "%X{X-B3-TraceId:-}",
                        "spanId": "%X{X-B3-SpanId:-}",
                        "spanExport": "%X{X-Span-Export:-}"
                        }
                    </pattern>
                </pattern>
            </providers>
        </encoder>
    </appender>
    <appender name="ASYNC-APPENDER-LOGSTASH" class="ch.qos.logback.classic.AsyncAppender">
        <appender-ref ref="APPENDER-LOGSTASH" />
        <!-- 设置异步阻塞队列的大小,为了不丢失日志建议设置的大一些,单机压测时100000是没问题的,应该不用担心OOM -->
        <queueSize>10000</queueSize>
        <!-- 设置丢弃DEBUG、TRACE、INFO日志的阀值,不丢失 -->
        <discardingThreshold>0</discardingThreshold>
        <!-- 设置队列入队时非阻塞,当队列满时会直接丢弃日志,但是对性能提升极大 -->
        <neverBlock>true</neverBlock>
    </appender>
    <!--输出到logstash:结束-->

    <!--
        开发环境日志级别为DEBUG
        level:用来设置打印级别
        五个常用打印级别从低至高依次为TRACE、DEBUG、INFO、WARN、ERROR
    -->
    <springProfile name="dev">
        <root>
            <!--输出到控制台-->
            <appender-ref ref="STDOUT"/>
            <!--异步非滚动输出到文件-->
            <appender-ref ref="ASYNC-APPENDER-FILEAPPENDER-INFO"/>
            <appender-ref ref="ASYNC-APPENDER-FILEAPPENDER-DEBUG"/>
            <appender-ref ref="ASYNC-APPENDER-FILEAPPENDER-ERROR"/>
            <!--异步滚动输出到文件:dev环境不开启-->
<!--            <appender-ref ref="ASYNC-APPENDER-ROLLINGFILEAPPENDER-INFO"/>-->
<!--            <appender-ref ref="ASYNC-APPENDER-ROLLINGFILEAPPENDER-DEBUG"/>-->
<!--            <appender-ref ref="ASYNC-APPENDER-ROLLINGFILEAPPENDER-ERROR"/>-->
            <!--异步滚动输出到logstash-->
            <appender-ref ref="ASYNC-APPENDER-LOGSTASH"/>
        </root>
    </springProfile>

    <!-- 测试环境日志级别为INFO -->
    <springProfile name="test">
        <root>
            <!--输出到控制台-->
            <appender-ref ref="STDOUT"/>
            <!--异步非滚动输出到文件-->
            <appender-ref ref="ASYNC-APPENDER-FILEAPPENDER-INFO"/>
            <appender-ref ref="ASYNC-APPENDER-FILEAPPENDER-DEBUG"/>
            <appender-ref ref="ASYNC-APPENDER-FILEAPPENDER-ERROR"/>
            <!--异步滚动输出到文件:test环境不开启-->
<!--            <appender-ref ref="ASYNC-APPENDER-ROLLINGFILEAPPENDER-INFO"/>-->
<!--            <appender-ref ref="ASYNC-APPENDER-ROLLINGFILEAPPENDER-DEBUG"/>-->
<!--            <appender-ref ref="ASYNC-APPENDER-ROLLINGFILEAPPENDER-ERROR"/>-->
            <!--异步滚动输出到logstash-->
            <appender-ref ref="ASYNC-APPENDER-LOGSTASH"/>
        </root>
    </springProfile>

    <!-- 生产环境日志级别为INFO -->
    <springProfile name="prod">
        <root>
            <!--输出到控制台-->
            <appender-ref ref="STDOUT"/>
            <!--异步非滚动输出到文件-->
            <appender-ref ref="ASYNC-APPENDER-FILEAPPENDER-INFO"/>
            <appender-ref ref="ASYNC-APPENDER-FILEAPPENDER-DEBUG"/>
            <appender-ref ref="ASYNC-APPENDER-FILEAPPENDER-ERROR"/>
            <!--异步滚动输出到文件-->
            <appender-ref ref="ASYNC-APPENDER-ROLLINGFILEAPPENDER-INFO"/>
            <appender-ref ref="ASYNC-APPENDER-ROLLINGFILEAPPENDER-DEBUG"/>
            <appender-ref ref="ASYNC-APPENDER-ROLLINGFILEAPPENDER-ERROR"/>
            <!--异步滚动输出到logstash-->
            <appender-ref ref="ASYNC-APPENDER-LOGSTASH"/>
        </root>
    </springProfile>

    <!-- rancher环境日志级别为INFO -->
    <springProfile name="rancher">
        <root>
            <!--输出到控制台-->
            <appender-ref ref="STDOUT"/>
            <!--异步非滚动输出到文件-->
            <appender-ref ref="ASYNC-APPENDER-FILEAPPENDER-INFO"/>
            <appender-ref ref="ASYNC-APPENDER-FILEAPPENDER-DEBUG"/>
            <appender-ref ref="ASYNC-APPENDER-FILEAPPENDER-ERROR"/>
            <!--异步滚动输出到文件-->
            <appender-ref ref="ASYNC-APPENDER-ROLLINGFILEAPPENDER-INFO"/>
            <appender-ref ref="ASYNC-APPENDER-ROLLINGFILEAPPENDER-DEBUG"/>
            <appender-ref ref="ASYNC-APPENDER-ROLLINGFILEAPPENDER-ERROR"/>
            <!--异步滚动输出到logstash-->
            <appender-ref ref="ASYNC-APPENDER-LOGSTASH"/>
        </root>
    </springProfile>
</configuration>

PaymentMapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >

<mapper namespace="org.openatom.springcloud.dao.PaymentDao">

    <!--第一种写法:parameterType不写全路径-->
    <insert id="create" parameterType="Payment" useGeneratedKeys="true" keyProperty="id">
        insert into payment(serial)  values(#{serial});
    </insert>

    <resultMap id="BaseResultMap" type="Payment">
        <id column="id" property="id" jdbcType="BIGINT"/>
        <id column="serial" property="serial" jdbcType="VARCHAR"/>
    </resultMap>
    <select id="getPaymentById" parameterType="Long" resultMap="BaseResultMap">
        select * from payment where id=#{id};
    </select>

    <!--第二种写法:parameterType的写法与第一种有区别-->
    <!--
    <insert id="create" parameterType="org.openatom.springcloud.entities.Payment" useGeneratedKeys="true" keyProperty="id">
        insert into payment(serial)  values(#{serial});
    </insert>

    <resultMap id="BaseResultMap" type="org.openatom.springcloud.entities.Payment">
        <id column="id" property="id" jdbcType="BIGINT"/>
        <id column="serial" property="serial" jdbcType="VARCHAR"/>
    </resultMap>
    <select id="getPaymentById" parameterType="Long" resultMap="BaseResultMap">
        select * from payment where id=#{id};
    </select>
    -->
</mapper>



20.6.6.编写模块dao

package org.openatom.springcloud.dao;

import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.openatom.springcloud.entities.Payment;

@Mapper
public interface PaymentDao {

    int create(Payment payment);

    Payment getPaymentById(@Param("id") Long id);
}

20.6.7.编写模块service

package org.openatom.springcloud.service;

import org.apache.ibatis.annotations.Param;
import org.openatom.springcloud.entities.Payment;

public interface PaymentService {

    int create(Payment payment);

    Payment getPaymentById(@Param("id") Long id);
}

20.6.8.编写模块service实现类

package org.openatom.springcloud.service.impl;

import org.openatom.springcloud.dao.PaymentDao;
import org.openatom.springcloud.service.PaymentService;
import org.springframework.stereotype.Service;
import org.openatom.springcloud.entities.Payment;

import javax.annotation.Resource;


@Service
public class PaymentServiceImpl implements PaymentService {

    @Resource
    private PaymentDao paymentDao;

    public int create(Payment payment) {
        return paymentDao.create(payment);
    }

    public Payment getPaymentById(Long id) {
        return paymentDao.getPaymentById(id);
    }
}

20.6.9.编写模块config

package org.openatom.springcloud.config;

import ch.qos.logback.core.PropertyDefinerBase;
import lombok.extern.slf4j.Slf4j;

import java.net.InetAddress;
import java.net.UnknownHostException;

@Slf4j
public class VirtualIpConfig extends PropertyDefinerBase {
    private static String virtualIp;
    static {
        try {
            virtualIp = InetAddress.getLocalHost().getHostAddress();
        } catch (UnknownHostException e) {
            log.error("获取日志Ip异常", e);
            virtualIp = null;
        }
    }

    @Override
    public String getPropertyValue() {
        return virtualIp;
    }
}

20.6.10.编写模块controller

package org.openatom.springcloud.controller;

import lombok.extern.slf4j.Slf4j;
import org.openatom.springcloud.service.PaymentService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.*;
import org.openatom.springcloud.entities.CommonResult;
import org.openatom.springcloud.entities.Payment;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.concurrent.TimeUnit;

@RestController
@Slf4j
public class PaymentController {

    @Resource
    private PaymentService paymentService;

    @Value("${server.port}")
    private String serverPort;

    @Autowired
    private HttpServletRequest request;

    //从配置文件中动态获取服务名称
    @Value("${spring.application.name}")
    private String APPLICATION_NAME;

    @PostMapping(value = "/provider/payment/create")
    public CommonResult create(@RequestBody Payment payment) {
        int result = paymentService.create(payment);
        log.info("*****插入结果:"+result);
        if(result > 0) {
            return new CommonResult(200,"插入数据库成功,serverPort: "+serverPort,result);
        }else{
            return new CommonResult(444,"插入数据库失败",null);
        }
    }

    /**
     * rancher扩容缩容测试专用方法
     * @param id
     * @return
     */
    @GetMapping(value = "/provider/payment/get/{id}")
    public CommonResult<Payment> getPaymentById(@PathVariable("id") Long id) {
        log.info("应用名称:" + APPLICATION_NAME
                + ",配置文件中的端口号11:" + serverPort + ",localAddr" + request.getLocalAddr());
        Payment payment = paymentService.getPaymentById(id);
        if(payment != null){
            return new CommonResult(200,"查询成功,localAddr: " + request.getLocalAddr(), payment);
        }else{
            return new CommonResult(444,"没有对应记录,查询ID: "+id,null);
        }
    }

    /**
     * 用来测试OpenFeign远程调用超时报异常的方法
     * @return
     */
    @GetMapping(value = "/provider/payment/openfeign/timeout")
    public String getPaymentByIdOpenFeignTimeout() {
        // 业务逻辑处理正确,但是需要耗费3秒钟
        try {
            TimeUnit.SECONDS.sleep(3);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return serverPort;
    }
}

20.6.11.编写模块主启动类

package org.openatom.springcloud;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;

/**
 * 支付接口提供端
 *  使用Eureka作为注册中心
 */
@EnableEurekaClient
@SpringBootApplication
public class BasicSamplePaymentServiceProviderClusterNode8009 {

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

}

20.7.搭建服务提供者第二个节点

20.7.1.模块简介

为综合案例搭建服务提供者的第二个节点,启动端口: 8010

20.7.2.模块目录结构

springcloud-basic-sample-provider-cluster-node-payment8010
|-- docker
|   •-- Dockerfile
|-- src
|   •-- main
|       |-- java
|       |   •-- org
|       |       •-- openatom
|       |           •-- springcloud
|       |               |-- config
|       |               |   •-- VirtualIpConfig.java
|       |               |-- controller
|       |               |   •-- PaymentController.java
|       |               |-- dao
|       |               |   •-- PaymentDao.java
|       |               |-- service
|       |               |   |-- impl
|       |               |   |   •-- PaymentServiceImpl.java
|       |               |   •-- PaymentService.java
|       |               •-- BasicSamplePaymentServiceProviderClusterNode8010.java
|       •-- resources
|           |-- dev
|           |   |-- mapper
|           |   |   •-- PaymentMapper.xml
|           |   |-- application-dev.yml
|           |   |-- application.yml
|           |   •-- logback-custom.xml
|           |-- prod
|           |   |-- mapper
|           |   |   •-- PaymentMapper.xml
|           |   |-- application-prod.yml
|           |   |-- application.yml
|           |   •-- logback-custom.xml
|           |-- rancher
|           |   |-- mapper
|           |   |   •-- PaymentMapper.xml
|           |   |-- application-rancher.yml
|           |   |-- application.yml
|           |   •-- logback-custom.xml
|           •-- test
|               |-- mapper
|               |   •-- PaymentMapper.xml
|               |-- application-test.yml
|               |-- application.yml
|               •-- logback-custom.xml
•-- pom.xml

20.7.3.创建模块

在父工程(springcloud-eureka)中创建一个名为springcloud-basic-sample-provider-cluster-node-payment8010的maven模块,注意:当前模块创建成功后,在父工程pom.xml中<modules></modules>中会自动生成有关当前模块的信息

20.7.4.编写模块pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>springcloud-eureka</artifactId>
        <groupId>org.openatom</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>springcloud-basic-sample-provider-cluster-node-payment8010</artifactId>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
        <!--设置当前服务端口-->
        <docker.container.port>8010</docker.container.port>
        <!--docker容器端口映射-->
        <docker.port.mapping>${docker.container.port}:${docker.container.port}</docker.port.mapping>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid-spring-boot-starter</artifactId>
        </dependency>
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jdbc</artifactId>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
        <!--引入公共的工程-->
        <dependency>
            <groupId>org.openatom</groupId>
            <artifactId>springcloud-api-commons</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
        <dependency>
            <groupId>net.logstash.logback</groupId>
            <artifactId>logstash-logback-encoder</artifactId>
        </dependency>
        <dependency>
            <groupId>de.codecentric</groupId>
            <artifactId>spring-boot-admin-starter-client</artifactId>
        </dependency>
        <!--包含了sleuth+zipkin-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-zipkin</artifactId>
        </dependency>
        <dependency>
            <groupId> org.springframework.boot </groupId>
            <artifactId>spring-boot-configuration-processor</artifactId>
            <optional> true </optional>
        </dependency>
    </dependencies>

    <!--热部署需要加这个-->
    <build>
        <finalName>${project.artifactId}</finalName>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <executions>
                    <execution>
                        <!--把当前插件repackage命令和maven的package绑定-->
                        <id>repackage-original</id>
                        <phase>package</phase>
                        <goals>
                            <goal>repackage</goal>
                        </goals>
                    </execution>
                </executions>
                <configuration>
                    <fork>true</fork>
                    <addResources>true</addResources>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-resources-plugin</artifactId>
                <configuration>
                    <encoding>UTF-8</encoding>
                    <delimiters>
                        <delimiter>@</delimiter>
                    </delimiters>
                    <useDefaultDelimiters>false</useDefaultDelimiters>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-antrun-plugin</artifactId>
                <executions>
                    <execution>
                        <id>del-jar</id>
                        <phase>clean</phase>
                        <configuration>
                            <tasks>
                                <!-- 这是将当前模块下的target下的jar包删除-->
                                <delete file="docker/${build.finalName}.jar"/>
                            </tasks>
                        </configuration>
                        <goals>
                            <goal>run</goal>
                        </goals>
                    </execution>
                    <execution>
                        <id>copy-jar</id>
                        <phase>install</phase>
                        <configuration>
                            <tasks>
                                <!-- 这是将当前模块下的target下的jar包copy到当前模块根目录下docker目录中-->
                                <copy todir="docker" file="target/${build.finalName}.jar"></copy>
                            </tasks>
                        </configuration>
                        <goals>
                            <goal>run</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
            <plugin>
                <groupId>io.fabric8</groupId>
                <artifactId>docker-maven-plugin</artifactId>
                <configuration>
                    <dockerHost>${docker.host}</dockerHost>
                    <removeMode>true</removeMode>
                    <!--
                        harbor镜像仓库认证配置
                        注意:不管是harbor中是公开项目还是私密项目,这个配置都要加,不加无法push成功
                    -->
                    <authConfig>
                        <username>${docker.registry.username}</username>
                        <password>${docker.registry.password}</password>
                    </authConfig>
                    <images>
                        <image>
                            <!--显示日志的时候-->
                            <!--<alias>spring-cloud-eureka</alias>-->
                            <!--如果只给docker本地镜像库中推送,格式为 命名空间/项目名称:tags名称,示例:项目artifactId/模块artifactId-->
                            <!--<name>${project.parent.artifactId}/${project.name}</name>-->
                            <!--
                                如果要同时给私服中推送,格式为 registry的ip:命名空间/项目名称:tags名称,示例:私服的ip:项目artifactId/模块artifactId
                                也可将registry单独写在下面
                            -->
                            <!--<name>镜像名称:${docker.registry}/${project.parent.artifactId}/${project.name}</name>-->
                            <name>${project.parent.artifactId}/${project.name}:latest</name>
                            <registry>${docker.registry.uri}</registry>
                            <!--定义镜像构建行为-->
                            <build>
                                <!-- 指定dockerfile文件的位置-->
                                <dockerFile>${project.basedir}/docker/Dockerfile</dockerFile>
                            </build>
                            <!-- 定义容器启动行为-->
                            <run>
                                <!--设置容器名,可采用通配符-->
                                <containerNamePattern>${project.parent.artifactId}_${project.build.finalName}</containerNamePattern>
                                <!--设置端口映射-->
                                <ports>
                                    <port>${docker.port.mapping}</port>
                                </ports>
                                <links>
                                    <link>mysql</link>
                                </links>
                            </run>
                        </image>
                    </images>
                    <buildArgs>
                        <!--docker私服地址-->
                        <DOCKER_REGISTRY_URL>${docker.registry.uri}</DOCKER_REGISTRY_URL>
                    </buildArgs>
                </configuration>
                <executions>
                    <!--如果想在项目install时构建镜像添加-->
                    <execution>
                        <id>build-image</id>
                        <phase>install</phase>
                        <goals>
                            <goal>build</goal>
                        </goals>
                    </execution>
                    <!--如果想在项目install时构建镜像添加-->
                    <execution>
                        <id>tag-image</id>
                        <phase>install</phase>
                        <goals>
                            <goal>tag</goal>
                        </goals>
                    </execution>
                    <!--如果想在项目install时推送镜像到私服添加-->
                    <execution>
                        <id>push-image</id>
                        <phase>install</phase>
                        <goals>
                            <goal>push</goal>
                        </goals>
                    </execution>
                    <!--如果想在项目install时推送镜像到私服后删除并docker中本地build的镜像添加-->
                    <execution>
                        <id>remove-image</id>
                        <phase>install</phase>
                        <goals>
                            <goal>remove</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
        <!--打包多环境-->
        <resources>
            <resource>
                <directory>src/main/resources</directory>
                <excludes>
                    <exclude>**/*.yml</exclude>
                    <exclude>**/*.xml</exclude>
                </excludes>
            </resource>
            <resource>
                <directory>src/main/resources/${profile.active}</directory>
                <!--引入所需环境的配置文件-->
                <filtering>true</filtering>
                <includes>
                    <include>application.yml</include>
                    <!--根据maven选择环境导入配置文件-->
                    <include>application-${profile.active}.yml</include>
                    <include>mapper/*.xml</include>
                    <include>*.xml</include>
                </includes>
            </resource>
        </resources>
    </build>
</project>

20.7.5.编写模块配置文件

dev环境配置文件
application.yml
#设置spring项目运行的环境
spring:
  profiles:
    active: '@profile.active@'


application-dev.yml
server:
  port: 8010 #访问端口
spring:
  application:
    name: SPRINGCLOUD-BASIC-SAMPLE-PROVIDER-PAYMENT-SERVICE-CLUSTER-DEV  #注意:服务名不要出现_
  devtools:
    restart:
      enabled: true
  # 将Client作为服务注册到SpringBootAdmin Server端,通过Server来监听项目的运行情况
  boot:
    admin:
      client:
        url: http://${eureka.instance.ip-address}:${server.port}
  zipkin:
    base-url: http://localhost:9411
  sleuth:
    sampler:
      probability: 1  # span的采样率,默认为 0.1,这个值介于0到1之间
  logging:
    level: info
  datasource:
    type: com.alibaba.druid.pool.DruidDataSource            # 当前数据源操作类型
    driver-class-name: com.mysql.cj.jdbc.Driver              # mysql驱动包
    url: jdbc:mysql://192.168.0.5:3306/payment?useUnicode=true&characterEncoding=utf-8&useSSL=false
    username: root
    password: Mysql123456_

eureka:
  client:
    register-with-eureka: true  #表示是否将自己注册进EurekaServer默认为true。
    fetchRegistry: true  #是否从EurekaServer抓取已有的注册信息,默认为true。单节点无所谓,集群必须设置为true才能配合ribbon使用负载均衡
    service-url:
      #单机版
      defaultZone: http://localhost:7005/eureka
      #集群版
      #defaultZone: http://eureka7002:7002/eureka,http://eureka7003:7003/eureka,http://eureka7004:7004/eureka
  instance:
    instance-id: SPRINGCLOUD-PROVIDER-PAYMENT-SERVICE-CLUSTER-NODE-PAYMENT8010-DEV #Eureka仪表盘中Instances currently registered with Eureka.Status显示的内容
    #当前微服务所在部署机器ip
    ip-address: localhost
    prefer-ip-address: true  #访问路径可以显示IP地址,点击Eureka仪表盘中Instances currently registered with Eureka.Status显示的内容地址栏是否显示IP地址
    lease-renewal-interval-in-seconds: 30 #Eureka客户端向服务端发送心跳的时间间隔,单位为秒(默认是30秒)
    lease-expiration-duration-in-seconds: 90 #Eureka服务端在收到最后一次心跳后等待时间上限,单位为秒(默认是90秒),超时将剔除服务

mybatis:
  mapperLocations: classpath:mapper/*.xml
  type-aliases-package: org.openatom.springcloud.entities    # 所有Entity别名类所在包

#配置文件修改说明-------------------------------------------------:开始
#注意:不同的部署环境需要修改的配置
#   1.${logback.path}  #修改日志存放位置,Linxu为/,Windows为\
#       修改原因: Linux和Windows目录结构不同
#配置文件修改说明-------------------------------------------------:结束

#自定义日志配置文件路径
logging:
  config: classpath:logback-custom.xml
  path: D:\repository\workspace\IDEA\PERSONAL\springcloud-eureka\log\ #所有日志存放在位置,加上\方便Linux环境下配置
  level:
    root: info #全局日志输出级别

logback:
  log-name: ${spring.application.name}
  append: false #是否启用append(追加到已经存在日志文件尾部),true:重启项目会追加新日志到之前日志,false:重启项目会清空之前的日志
  immediate-flush: true #是否启用immediateFlush(立即刷新),true:重启项目自动追加,false:重启项目会情况之前的日志
  deploy-machine-ip: ${eureka.instance.ip-address} #当前微服务所在部署机器ip

#logstash相关配置:开始
logstash:
  host: 192.168.0.4:5044 # logstash地址
  index: '@project.parent.artifactId@' # es中index名称
#logstash相关配置:结束

#actuator监控:开始
#通过下面的配置启用所有的监控端点,默认情况下,这些端点是禁用的;
management:
  endpoints:
    web:
      exposure:
        include: '*'
    enabled-by-default: true
  endpoint:
    health:
      show-details: always # 访问/actuator/health时,显示详细信息,而不是仅仅显示"status": "UP"
    # 日志文件路径:特别注意,此处无法配置日志文件路径,因为rancher会生成虚拟ip,这个虚拟ip是无法在这里获取的,
    #           但是虚拟ip是路径的一部分,所以这个路径无法拼接出来,所以这里无法配置日志文件路径
    #logfile:
    #  external-file:
#actuator监控:结束

logback-custom.xml
<?xml version="1.0" encoding="UTF-8"?>

<!--
    scan: 当此属性设置为true时,配置文件如果发生改变,将会被重新加载,默认值为true。
    scanPeriod: 设置监测配置文件是否有修改的时间间隔,如果没有给出时间单位,默认单位是毫秒。当scan为true时,此属性生效。默认的时间间隔为1分钟。
    debug: 当此属性设置为true时,将打印出logback内部日志信息,实时查看logback运行状态。默认值为false。
-->
<!-- 输出logback内部日志信息,每隔30s判断一下配置文件有没有更新,若更新,则重新加载 -->
<configuration scan="true" scanPeriod="30 seconds" debug="false">
    <!--从java代码中获取虚拟ip的值-->
    <!--获取当前微服务部署虚拟IP,如rancher为当前微服务分配的ip-->
    <define name="VIRTUAL_IP" class="org.openatom.springcloud.config.VirtualIpConfig"/>

    <!--从Spring容器中获取配置(Spring配置文件加载顺序:bootstrap.yml->logback.xml->application.yml)-->
    <!--获取当前微服务部署机器ip-->
    <springProperty name="MACHINE_IP" scope="context" source="logback.deploy-machine-ip"/>
    <!--应用名称-->
    <springProperty name="LOG_NAME" scope="context" source="logback.log-name"/>
    <!--是否启用append-->
    <springProperty name="IS_APPEND" scope="context" source="logback.append"/>
    <!--是否启用立即刷新-->
    <springProperty name="IS_IMMEDIATEFLUSH" scope="context" source="logback.immediate-flush"/>
    <springProperty name="LOG_PATH" scope="context" source="logging.path"/>
    <!--logstash地址-->
    <springProperty name="LOGSTASH_HOST" scope="context" source="logstash.host"/>
    <!--索引名称-->
    <springProperty name="INDEX_NAME" scope="context" source="logstash.index"/>


    <!-- name:变量的名称,可以随意起名,但建议名字要简明直译;value:变量的值;在配置文件中,我们可以用 ${} 的方式来使用,将变量引入到其他节点中去。-->
    <!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度 %msg:日志消息,%n是换行符-->
    <!--控制台日志输出预选样式-->
    <property name="CONSOLE_LOG_PATTERN_1" value="%red(%d{yyyy-MM-dd HH:mm:ss.SSS}) %green([%thread]) [machineIp:${MACHINE_IP} virtualIp:${VIRTUAL_IP}] [TraceId:%X{X-B3-TraceId:-} SpanId:%X{X-B3-SpanId:-} %highlight(%-5level) %boldMagenta(%logger{10}): %cyan(%msg%n)"/>
    <property name="CONSOLE_LOG_PATTERN_2" value="%yellow(%date{yyyy-MM-dd HH:mm:ss}) [machineIp:${MACHINE_IP} virtualIp:${VIRTUAL_IP}] [TraceId:%X{X-B3-TraceId:-} SpanId:%X{X-B3-SpanId:-} %highlight([%-5level]) %green(%logger) %msg%n"/>
    <property name="CONSOLE_LOG_PATTERN_3" value="%date{yyyy-MM-dd HH:mm:ss} [machineIp:${MACHINE_IP} virtualIp:${VIRTUAL_IP}] [TraceId:%X{X-B3-TraceId:-} SpanId:%X{X-B3-SpanId:-} Span-Export:%X{X-Span-Export:-}]  %green(%-5level) %boldMagenta(${PID:-}) -- [%+20thread] %cyan(%logger{20}) %line       : %msg%n"/>
    <!--文件中日志输出预选样式-->
    <property name="FILE_LOG_PATTERN_1" value="%d{yyyyMMdd:HH:mm:ss.SSS} [machineIp:${MACHINE_IP} virtualIp:${VIRTUAL_IP}] [TraceId:%X{X-B3-TraceId:-} SpanId:%X{X-B3-SpanId:-} [%thread] %-5level  %msg%n"/>

    <!--控制台日志输出格式-->
    <property name="CONSOLE_LOG_PATTERN" value="${CONSOLE_LOG_PATTERN_3}"/>
    <!--文件中日志输出格式-->
    <property name="FILE_LOG_PATTERN" value="${FILE_LOG_PATTERN_1}"/>
    <!--日志名称-->
    <!--定义默认日志输出级别-->
    <property name="LOG_OUTPUT_LEVEL" value="${LOG_LEVEL}" />
    <!--定义默认日志输出编码-->
    <property name="ENCODING" value="UTF-8" />

    <!-- 控制台输出:开始 -->
    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
        <!-- 用来设置日志的输入格式,使用“%+转换符”的方式,如果要输出”%”则必须使用”\”进行转义。-->
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <!-- 格式化输出:https://logback.qos.ch/manual/layouts.html
                 %d 表示日期,
                 %thread 表示线程名,
                 %level 日志级别从左显示5个字符宽度,
                 %t 线程名
                 %file:%line 文件名+行号,
                 %m 日志消息,%n是换行符
                 %X{traceId}:自定义设置的参数,后面会说。
            -->
            <pattern>${CONSOLE_LOG_PATTERN}</pattern>
            <charset>${ENCODING}</charset>
        </encoder>
    </appender>
    <!-- 控制台输出:结束 -->

    <!--输出到文件:开始-->
    <!-- 将项目本次运行INFO日志同步输出到文件,会自动清空文件中上一次的日志 -->
    <appender name="APPENDER-FILEAPPENDER-INFO" class="ch.qos.logback.core.FileAppender">
        <!-- 过滤器,只记录 info 级别以上的日志 -->
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <level>INFO</level>
        </filter>
        <!-- 写入的日志文件名,可以使相对目录也可以是绝对目录,如果上级目录不存在则自动创建 -->
        <file>${LOG_PATH}/${MACHINE_IP}/${VIRTUAL_IP}/${LOG_NAME}-info.log</file>
        <!-- 如果为true表示日志被追加到文件结尾,如果是false表示清空文件 -->
        <append>${IS_APPEND}</append>
        <!--立即刷新,设置成false可以提高日志吞吐量-->
        <immediateFlush>${IS_IMMEDIATEFLUSH}</immediateFlush>
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <pattern>${FILE_LOG_PATTERN}</pattern>
            <charset>${ENCODING}</charset>
        </encoder>
    </appender>

    <!-- 将项目本次运行INFO日志异步输出到文件,会自动清空文件中上一次的日志 -->
    <appender name="ASYNC-APPENDER-FILEAPPENDER-INFO" class="ch.qos.logback.classic.AsyncAppender">
        <appender-ref ref="APPENDER-FILEAPPENDER-INFO" />
        <!-- 设置异步阻塞队列的大小,为了不丢失日志建议设置的大一些,单机压测时100000是没问题的,应该不用担心OOM -->
        <queueSize>10000</queueSize>
        <!-- 设置丢弃DEBUG、TRACE、INFO日志的阀值,不丢失 -->
        <discardingThreshold>0</discardingThreshold>
        <!-- 设置队列入队时非阻塞,当队列满时会直接丢弃日志,但是对性能提升极大 -->
        <neverBlock>${IS_IMMEDIATEFLUSH}</neverBlock>
    </appender>

    <!-- 将项目本次运行DEBUG日志同步输出到文件,会自动清空文件中上一次的日志 -->
    <appender name="APPENDER-FILEAPPENDER-DEBUG" class="ch.qos.logback.core.FileAppender">
        <!-- 过滤器,只记录 info 级别以上的日志 -->
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <level>DEBUG</level>
        </filter>
        <!-- 写入的日志文件名,可以使相对目录也可以是绝对目录,如果上级目录不存在则自动创建 -->
        <file>${LOG_PATH}/${MACHINE_IP}/${VIRTUAL_IP}/${LOG_NAME}-debug.log</file>
        <!-- 如果为true表示日志被追加到文件结尾,如果是false表示清空文件 -->
        <append>${IS_APPEND}</append>
        <!--立即刷新,设置成false可以提高日志吞吐量-->
        <immediateFlush>true</immediateFlush>
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <pattern>${FILE_LOG_PATTERN}</pattern>
            <charset>${ENCODING}</charset>
        </encoder>
    </appender>

    <!-- 将项目本次运行DEBUG日志异步输出到文件,会自动清空文件中上一次的日志 -->
    <appender name="ASYNC-APPENDER-FILEAPPENDER-DEBUG" class="ch.qos.logback.classic.AsyncAppender">
        <appender-ref ref="APPENDER-FILEAPPENDER-DEBUG" />
        <!-- 设置异步阻塞队列的大小,为了不丢失日志建议设置的大一些,单机压测时100000是没问题的,应该不用担心OOM -->
        <queueSize>10000</queueSize>
        <!-- 设置丢弃DEBUG、TRACE、INFO日志的阀值,不丢失 -->
        <discardingThreshold>0</discardingThreshold>
        <!-- 设置队列入队时非阻塞,当队列满时会直接丢弃日志,但是对性能提升极大 -->
        <neverBlock>true</neverBlock>
    </appender>

    <!-- 将项目本次运行ERROR日志同步输出到文件,会自动清空文件中上一次的日志 -->
    <appender name="APPENDER-FILEAPPENDER-ERROR" class="ch.qos.logback.core.FileAppender">
        <!-- 过滤器,只记录 info 级别以上的日志 -->
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <level>DEBUG</level>
        </filter>
        <!-- 写入的日志文件名,可以使相对目录也可以是绝对目录,如果上级目录不存在则自动创建 -->
        <file>${LOG_PATH}/${MACHINE_IP}/${VIRTUAL_IP}/${LOG_NAME}-error.log</file>
        <!-- 如果为true表示日志被追加到文件结尾,如果是false表示清空文件 -->
        <append>${IS_APPEND}</append>
        <!--立即刷新,设置成false可以提高日志吞吐量-->
        <immediateFlush>${IS_IMMEDIATEFLUSH}</immediateFlush>
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <pattern>${FILE_LOG_PATTERN}</pattern>
            <charset>${ENCODING}</charset>
        </encoder>
    </appender>

    <!-- 将项目本次运行ERROR日志异步输出到文件,会自动清空文件中上一次的日志 -->
    <appender name="ASYNC-APPENDER-FILEAPPENDER-ERROR" class="ch.qos.logback.classic.AsyncAppender">
        <appender-ref ref="APPENDER-FILEAPPENDER-ERROR" />
        <!-- 设置异步阻塞队列的大小,为了不丢失日志建议设置的大一些,单机压测时100000是没问题的,应该不用担心OOM -->
        <queueSize>10000</queueSize>
        <!-- 设置丢弃DEBUG、TRACE、INFO日志的阀值,不丢失 -->
        <discardingThreshold>0</discardingThreshold>
        <!-- 设置队列入队时非阻塞,当队列满时会直接丢弃日志,但是对性能提升极大 -->
        <neverBlock>true</neverBlock>
    </appender>
    <!--输出到文件:结束-->


    <!--滚动输出到文件(按照天保存):开始-->
    <!-- 将项目本次运行INFO日志同步输出到文件,按照每天生成日志文件,会自动拼接上一次日志 -->
    <appender name="APPENDER-ROLLINGFILEAPPENDER-INFO" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <!-- 过滤器,只记录 info 级别以上的日志 -->
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <level>INFO</level>
        </filter>
        <!--立即刷新,设置成false可以提高日志吞吐量-->
        <immediateFlush>false</immediateFlush>
        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
            <!-- 日志文件输出的文件名:
                %d:可以包含一个Java.text.SimpleDateFormat指定的时间格式
                %i:自增数字
            -->
            <fileNamePattern>${LOG_PATH}/${MACHINE_IP}/${VIRTUAL_IP}/HISTORY/${LOG_NAME}-info-%d{yyyy-MM-dd}-index%i.log</fileNamePattern>
            <!-- 日志文件保存历史数量:控制保留的归档文件的最大数量,如果超出数量就删除旧文件 -->
            <maxHistory>10</maxHistory>
            <!-- 文件大小超过100MB归档 -->
            <maxFileSize>20MB</maxFileSize>
        </rollingPolicy>
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <pattern>${FILE_LOG_PATTERN}</pattern>
            <charset>${ENCODING}</charset>
        </encoder>
    </appender>

    <!-- 将项目本次运行INFO日志异步输出到文件,按照每天生成日志文件,会自动拼接上一次日志 -->
    <appender name="ASYNC-APPENDER-ROLLINGFILEAPPENDER-INFO" class="ch.qos.logback.classic.AsyncAppender">
        <appender-ref ref="APPENDER-ROLLINGFILEAPPENDER-INFO" />
        <!-- 设置异步阻塞队列的大小,为了不丢失日志建议设置的大一些,单机压测时100000是没问题的,应该不用担心OOM -->
        <queueSize>10000</queueSize>
        <!-- 设置丢弃DEBUG、TRACE、INFO日志的阀值,不丢失 -->
        <discardingThreshold>0</discardingThreshold>
        <!-- 设置队列入队时非阻塞,当队列满时会直接丢弃日志,但是对性能提升极大 -->
        <neverBlock>true</neverBlock>
    </appender>

    <!-- 将项目本次运行DEBUG日志同步输出到文件,按照每天生成日志文件,会自动拼接上一次日志 -->
    <appender name="APPENDER-ROLLINGFILEAPPENDER-DEBUG" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <!-- 过滤器,只记录 info 级别以上的日志 -->
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <level>DEBUG</level>
        </filter>
        <!--立即刷新,设置成false可以提高日志吞吐量-->
        <immediateFlush>false</immediateFlush>
        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
            <!-- 日志文件输出的文件名:
                %d:可以包含一个Java.text.SimpleDateFormat指定的时间格式
                %i:自增数字
            -->
            <fileNamePattern>${LOG_PATH}/${MACHINE_IP}/${VIRTUAL_IP}/HISTORY/${LOG_NAME}-debug-%d{yyyy-MM-dd}-index%i.log</fileNamePattern>
            <!-- 日志文件保存历史数量:控制保留的归档文件的最大数量,如果超出数量就删除旧文件 -->
            <maxHistory>10</maxHistory>
            <!-- 文件大小超过100MB归档 -->
            <maxFileSize>20MB</maxFileSize>
        </rollingPolicy>
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <pattern>${FILE_LOG_PATTERN}</pattern>
            <charset>${ENCODING}</charset>
        </encoder>
    </appender>

    <!-- 将项目本次运行DEBUG日志异步输出到文件,按照每天生成日志文件,会自动拼接上一次日志 -->
    <appender name="ASYNC-APPENDER-ROLLINGFILEAPPENDER-DEBUG" class="ch.qos.logback.classic.AsyncAppender">
        <appender-ref ref="APPENDER-ROLLINGFILEAPPENDER-DEBUG" />
        <!-- 设置异步阻塞队列的大小,为了不丢失日志建议设置的大一些,单机压测时100000是没问题的,应该不用担心OOM -->
        <queueSize>10000</queueSize>
        <!-- 设置丢弃DEBUG、TRACE、INFO日志的阀值,不丢失 -->
        <discardingThreshold>0</discardingThreshold>
        <!-- 设置队列入队时非阻塞,当队列满时会直接丢弃日志,但是对性能提升极大 -->
        <neverBlock>true</neverBlock>
    </appender>

    <!-- 将项目本次运行ERROR日志同步输出到文件,按照每天生成日志文件,会自动拼接上一次日志 -->
    <appender name="APPENDER-ROLLINGFILEAPPENDER-ERROR" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <!-- 过滤器,只记录error级别的日志 -->
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>ERROR</level>
            <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>
        <!--立即刷新,设置成false可以提高日志吞吐量-->
        <immediateFlush>false</immediateFlush>
        <!-- 每天生成一个日志文件,保存30天的日志文件 -->
        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
            <!-- 日志文件输出的文件名:按天回滚 daily -->
            <fileNamePattern>${LOG_PATH}/${MACHINE_IP}/${VIRTUAL_IP}/HISTORY/${LOG_NAME}-error-%d{yyyy-MM-dd}-index%i.log</fileNamePattern>
            <!-- 日志文件保留天数 -->
            <maxHistory>10</maxHistory>
            <!-- 文件大小超过100MB归档 -->
            <maxFileSize>20MB</maxFileSize>
        </rollingPolicy>
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <pattern>${FILE_LOG_PATTERN}</pattern>
            <charset>utf8</charset>
        </encoder>
    </appender>

    <appender name="ASYNC-APPENDER-ROLLINGFILEAPPENDER-ERROR" class="ch.qos.logback.classic.AsyncAppender">
        <appender-ref ref="APPENDER-ROLLINGFILEAPPENDER-ERROR" />
        <!-- 设置异步阻塞队列的大小,为了不丢失日志建议设置的大一些,单机压测时100000是没问题的,应该不用担心OOM -->
        <queueSize>10000</queueSize>
        <!-- 设置丢弃DEBUG、TRACE、INFO日志的阀值,不丢失 -->
        <discardingThreshold>0</discardingThreshold>
        <!-- 设置队列入队时非阻塞,当队列满时会直接丢弃日志,但是对性能提升极大 -->
        <neverBlock>true</neverBlock>
    </appender>
    <!--滚动输出到文件(按照天保存):结束-->

    <!--输出到LOGSTASH:开始-->
    <!-- 将项目本次运行ERROR日志同步输出到文件,按照每天生成日志文件,会自动拼接上一次日志 -->
    <appender name="APPENDER-LOGSTASH" class="net.logstash.logback.appender.LogstashTcpSocketAppender">
        <!--  logstash服务器地址-->
        <destination>${LOGSTASH_HOST}</destination>
        <encoder class="net.logstash.logback.encoder.LoggingEventCompositeJsonEncoder">
            <providers>
                <pattern>
                    <pattern>
                        {
                        "appName":"${INDEX_NAME}",
                        "machineIp":"${MACHINE_IP}",
                        "virtualIp":"${VIRTUAL_IP}",
                        "serviceName":"${LOG_NAME}",
                        "timestamp": "%date{\"yyyy-MM-dd'T'HH:mm:ss,SSSZ\"}",
                        "logLevel":"%level",
                        "message":"%msg%n",
                        "traceId": "%X{X-B3-TraceId:-}",
                        "spanId": "%X{X-B3-SpanId:-}",
                        "spanExport": "%X{X-Span-Export:-}"
                        }
                    </pattern>
                </pattern>
            </providers>
        </encoder>
    </appender>
    <appender name="ASYNC-APPENDER-LOGSTASH" class="ch.qos.logback.classic.AsyncAppender">
        <appender-ref ref="APPENDER-LOGSTASH" />
        <!-- 设置异步阻塞队列的大小,为了不丢失日志建议设置的大一些,单机压测时100000是没问题的,应该不用担心OOM -->
        <queueSize>10000</queueSize>
        <!-- 设置丢弃DEBUG、TRACE、INFO日志的阀值,不丢失 -->
        <discardingThreshold>0</discardingThreshold>
        <!-- 设置队列入队时非阻塞,当队列满时会直接丢弃日志,但是对性能提升极大 -->
        <neverBlock>true</neverBlock>
    </appender>
    <!--输出到logstash:结束-->

    <!--
        开发环境日志级别为DEBUG
        level:用来设置打印级别
        五个常用打印级别从低至高依次为TRACE、DEBUG、INFO、WARN、ERROR
    -->
    <springProfile name="dev">
        <root>
            <!--输出到控制台-->
            <appender-ref ref="STDOUT"/>
            <!--异步非滚动输出到文件-->
            <appender-ref ref="ASYNC-APPENDER-FILEAPPENDER-INFO"/>
            <appender-ref ref="ASYNC-APPENDER-FILEAPPENDER-DEBUG"/>
            <appender-ref ref="ASYNC-APPENDER-FILEAPPENDER-ERROR"/>
            <!--异步滚动输出到文件:dev环境不开启-->
<!--            <appender-ref ref="ASYNC-APPENDER-ROLLINGFILEAPPENDER-INFO"/>-->
<!--            <appender-ref ref="ASYNC-APPENDER-ROLLINGFILEAPPENDER-DEBUG"/>-->
<!--            <appender-ref ref="ASYNC-APPENDER-ROLLINGFILEAPPENDER-ERROR"/>-->
            <!--异步滚动输出到logstash-->
            <appender-ref ref="ASYNC-APPENDER-LOGSTASH"/>
        </root>
    </springProfile>

    <!-- 测试环境日志级别为INFO -->
    <springProfile name="test">
        <root>
            <!--输出到控制台-->
            <appender-ref ref="STDOUT"/>
            <!--异步非滚动输出到文件-->
            <appender-ref ref="ASYNC-APPENDER-FILEAPPENDER-INFO"/>
            <appender-ref ref="ASYNC-APPENDER-FILEAPPENDER-DEBUG"/>
            <appender-ref ref="ASYNC-APPENDER-FILEAPPENDER-ERROR"/>
            <!--异步滚动输出到文件:test环境不开启-->
<!--            <appender-ref ref="ASYNC-APPENDER-ROLLINGFILEAPPENDER-INFO"/>-->
<!--            <appender-ref ref="ASYNC-APPENDER-ROLLINGFILEAPPENDER-DEBUG"/>-->
<!--            <appender-ref ref="ASYNC-APPENDER-ROLLINGFILEAPPENDER-ERROR"/>-->
            <!--异步滚动输出到logstash-->
            <appender-ref ref="ASYNC-APPENDER-LOGSTASH"/>
        </root>
    </springProfile>

    <!-- 生产环境日志级别为INFO -->
    <springProfile name="prod">
        <root>
            <!--输出到控制台-->
            <appender-ref ref="STDOUT"/>
            <!--异步非滚动输出到文件-->
            <appender-ref ref="ASYNC-APPENDER-FILEAPPENDER-INFO"/>
            <appender-ref ref="ASYNC-APPENDER-FILEAPPENDER-DEBUG"/>
            <appender-ref ref="ASYNC-APPENDER-FILEAPPENDER-ERROR"/>
            <!--异步滚动输出到文件-->
            <appender-ref ref="ASYNC-APPENDER-ROLLINGFILEAPPENDER-INFO"/>
            <appender-ref ref="ASYNC-APPENDER-ROLLINGFILEAPPENDER-DEBUG"/>
            <appender-ref ref="ASYNC-APPENDER-ROLLINGFILEAPPENDER-ERROR"/>
            <!--异步滚动输出到logstash-->
            <appender-ref ref="ASYNC-APPENDER-LOGSTASH"/>
        </root>
    </springProfile>

    <!-- rancher环境日志级别为INFO -->
    <springProfile name="rancher">
        <root>
            <!--输出到控制台-->
            <appender-ref ref="STDOUT"/>
            <!--异步非滚动输出到文件-->
            <appender-ref ref="ASYNC-APPENDER-FILEAPPENDER-INFO"/>
            <appender-ref ref="ASYNC-APPENDER-FILEAPPENDER-DEBUG"/>
            <appender-ref ref="ASYNC-APPENDER-FILEAPPENDER-ERROR"/>
            <!--异步滚动输出到文件-->
            <appender-ref ref="ASYNC-APPENDER-ROLLINGFILEAPPENDER-INFO"/>
            <appender-ref ref="ASYNC-APPENDER-ROLLINGFILEAPPENDER-DEBUG"/>
            <appender-ref ref="ASYNC-APPENDER-ROLLINGFILEAPPENDER-ERROR"/>
            <!--异步滚动输出到logstash-->
            <appender-ref ref="ASYNC-APPENDER-LOGSTASH"/>
        </root>
    </springProfile>
</configuration>

PaymentMapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >

<mapper namespace="org.openatom.springcloud.dao.PaymentDao">

    <!--第一种写法:parameterType不写全路径-->
    <insert id="create" parameterType="Payment" useGeneratedKeys="true" keyProperty="id">
        insert into payment(serial)  values(#{serial});
    </insert>

    <resultMap id="BaseResultMap" type="Payment">
        <id column="id" property="id" jdbcType="BIGINT"/>
        <id column="serial" property="serial" jdbcType="VARCHAR"/>
    </resultMap>
    <select id="getPaymentById" parameterType="Long" resultMap="BaseResultMap">
        select * from payment where id=#{id};
    </select>

    <!--第二种写法:parameterType的写法与第一种有区别-->
    <!--
    <insert id="create" parameterType="org.openatom.springcloud.entities.Payment" useGeneratedKeys="true" keyProperty="id">
        insert into payment(serial)  values(#{serial});
    </insert>

    <resultMap id="BaseResultMap" type="org.openatom.springcloud.entities.Payment">
        <id column="id" property="id" jdbcType="BIGINT"/>
        <id column="serial" property="serial" jdbcType="VARCHAR"/>
    </resultMap>
    <select id="getPaymentById" parameterType="Long" resultMap="BaseResultMap">
        select * from payment where id=#{id};
    </select>
    -->
</mapper>



prod环境配置文件
application.yml
#设置spring项目运行的环境
spring:
  profiles:
    active: '@profile.active@'


application-prod.yml
server:
  port: 8010 #访问端口
spring:
  application:
    name: SPRINGCLOUD-BASIC-SAMPLE-PROVIDER-PAYMENT-SERVICE-CLUSTER-PROD  #注意:服务名不要出现_
  devtools:
    restart:
      enabled: true
  # 将Client作为服务注册到SpringBootAdmin Server端,通过Server来监听项目的运行情况
  boot:
    admin:
      client:
        url: http://${eureka.instance.ip-address}:${server.port}
  logging:
    level: info
  datasource:
    type: com.alibaba.druid.pool.DruidDataSource            # 当前数据源操作类型
    driver-class-name: com.mysql.cj.jdbc.Driver              # mysql驱动包
    #192.168.0.2:docker容器外部数据库环境,192.168.0.4:docker容器内部数据库环境
    url: jdbc:mysql://192.168.0.4:3306/payment?useUnicode=true&characterEncoding=utf-8&useSSL=false
    username: root
    password: 123456

eureka:
  client:
    register-with-eureka: true  #表示是否将自己注册进EurekaServer默认为true。
    fetchRegistry: true  #是否从EurekaServer抓取已有的注册信息,默认为true。单节点无所谓,集群必须设置为true才能配合ribbon使用负载均衡
    service-url:
      #单机版
      defaultZone: http://192.168.0.4:7005/eureka
      #集群版
      #defaultZone: http://eureka7002:7002/eureka,http://eureka7003:7003/eureka,http://eureka7004:7004/eureka
  instance:
    instance-id: SPRINGCLOUD-PROVIDER-PAYMENT-SERVICE-CLUSTER-NODE-PAYMENT8010-PROD #Eureka仪表盘中Instances currently registered with Eureka.Status显示的内容
    #当前微服务所在部署机器ip
    ip-address: 192.168.0.4
    prefer-ip-address: true  #访问路径可以显示IP地址,点击Eureka仪表盘中Instances currently registered with Eureka.Status显示的内容地址栏是否显示IP地址
    lease-renewal-interval-in-seconds: 30 #Eureka客户端向服务端发送心跳的时间间隔,单位为秒(默认是30秒)
    lease-expiration-duration-in-seconds: 90 #Eureka服务端在收到最后一次心跳后等待时间上限,单位为秒(默认是90秒),超时将剔除服务

mybatis:
  mapperLocations: classpath:mapper/*.xml
  type-aliases-package: org.openatom.springcloud.entities    # 所有Entity别名类所在包

#配置文件修改说明-------------------------------------------------:开始
#注意:不同的部署环境需要修改的配置
#   1.${logback.path}  #修改日志存放位置,Linxu为/,Windows为\
#       修改原因: Linux和Windows目录结构不同
#配置文件修改说明-------------------------------------------------:结束

#自定义日志配置文件路径
logging:
  config: classpath:logback-custom.xml
  path: /logs #所有日志存放在位置,加上\方便Linux环境下配置
  level:
    root: info #全局日志输出级别

logback:
  log-name: ${spring.application.name}
  append: false #是否启用append(追加到已经存在日志文件尾部),true:重启项目会追加新日志到之前日志,false:重启项目会清空之前的日志
  immediate-flush: true #是否启用immediateFlush(立即刷新),true:重启项目自动追加,false:重启项目会情况之前的日志
  deploy-machine-ip: ${eureka.instance.ip-address} #当前微服务所在部署机器ip

#logstash相关配置:开始
logstash:
  host: 192.168.0.4:5044 # logstash地址
  index: '@project.parent.artifactId@' # es中index名称
#logstash相关配置:结束

#actuator监控:开始
#通过下面的配置启用所有的监控端点,默认情况下,这些端点是禁用的;
management:
  endpoints:
    web:
      exposure:
        include: '*'
    enabled-by-default: true
  endpoint:
    health:
      show-details: always # 访问/actuator/health时,显示详细信息,而不是仅仅显示"status": "UP"
    # 日志文件路径:特别注意,此处无法配置日志文件路径,因为rancher会生成虚拟ip,这个虚拟ip是无法在这里获取的,
    #           但是虚拟ip是路径的一部分,所以这个路径无法拼接出来,所以这里无法配置日志文件路径
    #logfile:
    #  external-file:
#actuator监控:结束

logback-custom.xml
<?xml version="1.0" encoding="UTF-8"?>

<!--
    scan: 当此属性设置为true时,配置文件如果发生改变,将会被重新加载,默认值为true。
    scanPeriod: 设置监测配置文件是否有修改的时间间隔,如果没有给出时间单位,默认单位是毫秒。当scan为true时,此属性生效。默认的时间间隔为1分钟。
    debug: 当此属性设置为true时,将打印出logback内部日志信息,实时查看logback运行状态。默认值为false。
-->
<!-- 输出logback内部日志信息,每隔30s判断一下配置文件有没有更新,若更新,则重新加载 -->
<configuration scan="true" scanPeriod="30 seconds" debug="false">
    <!--从java代码中获取虚拟ip的值-->
    <!--获取当前微服务部署虚拟IP,如rancher为当前微服务分配的ip-->
    <define name="VIRTUAL_IP" class="org.openatom.springcloud.config.VirtualIpConfig"/>

    <!--从Spring容器中获取配置(Spring配置文件加载顺序:bootstrap.yml->logback.xml->application.yml)-->
    <!--获取当前微服务部署机器ip-->
    <springProperty name="MACHINE_IP" scope="context" source="logback.deploy-machine-ip"/>
    <!--应用名称-->
    <springProperty name="LOG_NAME" scope="context" source="logback.log-name"/>
    <!--是否启用append-->
    <springProperty name="IS_APPEND" scope="context" source="logback.append"/>
    <!--是否启用立即刷新-->
    <springProperty name="IS_IMMEDIATEFLUSH" scope="context" source="logback.immediate-flush"/>
    <springProperty name="LOG_PATH" scope="context" source="logging.path"/>
    <!--logstash地址-->
    <springProperty name="LOGSTASH_HOST" scope="context" source="logstash.host"/>
    <!--索引名称-->
    <springProperty name="INDEX_NAME" scope="context" source="logstash.index"/>


    <!-- name:变量的名称,可以随意起名,但建议名字要简明直译;value:变量的值;在配置文件中,我们可以用 ${} 的方式来使用,将变量引入到其他节点中去。-->
    <!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度 %msg:日志消息,%n是换行符-->
    <!--控制台日志输出预选样式-->
    <property name="CONSOLE_LOG_PATTERN_1" value="%red(%d{yyyy-MM-dd HH:mm:ss.SSS}) %green([%thread]) [machineIp:${MACHINE_IP} virtualIp:${VIRTUAL_IP}] [TraceId:%X{X-B3-TraceId:-} SpanId:%X{X-B3-SpanId:-} %highlight(%-5level) %boldMagenta(%logger{10}): %cyan(%msg%n)"/>
    <property name="CONSOLE_LOG_PATTERN_2" value="%yellow(%date{yyyy-MM-dd HH:mm:ss}) [machineIp:${MACHINE_IP} virtualIp:${VIRTUAL_IP}] [TraceId:%X{X-B3-TraceId:-} SpanId:%X{X-B3-SpanId:-} %highlight([%-5level]) %green(%logger) %msg%n"/>
    <property name="CONSOLE_LOG_PATTERN_3" value="%date{yyyy-MM-dd HH:mm:ss} [machineIp:${MACHINE_IP} virtualIp:${VIRTUAL_IP}] [TraceId:%X{X-B3-TraceId:-} SpanId:%X{X-B3-SpanId:-} Span-Export:%X{X-Span-Export:-}]  %green(%-5level) %boldMagenta(${PID:-}) -- [%+20thread] %cyan(%logger{20}) %line       : %msg%n"/>
    <!--文件中日志输出预选样式-->
    <property name="FILE_LOG_PATTERN_1" value="%d{yyyyMMdd:HH:mm:ss.SSS} [machineIp:${MACHINE_IP} virtualIp:${VIRTUAL_IP}] [TraceId:%X{X-B3-TraceId:-} SpanId:%X{X-B3-SpanId:-} [%thread] %-5level  %msg%n"/>

    <!--控制台日志输出格式-->
    <property name="CONSOLE_LOG_PATTERN" value="${CONSOLE_LOG_PATTERN_3}"/>
    <!--文件中日志输出格式-->
    <property name="FILE_LOG_PATTERN" value="${FILE_LOG_PATTERN_1}"/>
    <!--日志名称-->
    <!--定义默认日志输出级别-->
    <property name="LOG_OUTPUT_LEVEL" value="${LOG_LEVEL}" />
    <!--定义默认日志输出编码-->
    <property name="ENCODING" value="UTF-8" />

    <!-- 控制台输出:开始 -->
    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
        <!-- 用来设置日志的输入格式,使用“%+转换符”的方式,如果要输出”%”则必须使用”\”进行转义。-->
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <!-- 格式化输出:https://logback.qos.ch/manual/layouts.html
                 %d 表示日期,
                 %thread 表示线程名,
                 %level 日志级别从左显示5个字符宽度,
                 %t 线程名
                 %file:%line 文件名+行号,
                 %m 日志消息,%n是换行符
                 %X{traceId}:自定义设置的参数,后面会说。
            -->
            <pattern>${CONSOLE_LOG_PATTERN}</pattern>
            <charset>${ENCODING}</charset>
        </encoder>
    </appender>
    <!-- 控制台输出:结束 -->

    <!--输出到文件:开始-->
    <!-- 将项目本次运行INFO日志同步输出到文件,会自动清空文件中上一次的日志 -->
    <appender name="APPENDER-FILEAPPENDER-INFO" class="ch.qos.logback.core.FileAppender">
        <!-- 过滤器,只记录 info 级别以上的日志 -->
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <level>INFO</level>
        </filter>
        <!-- 写入的日志文件名,可以使相对目录也可以是绝对目录,如果上级目录不存在则自动创建 -->
        <file>${LOG_PATH}/${MACHINE_IP}/${VIRTUAL_IP}/${LOG_NAME}-info.log</file>
        <!-- 如果为true表示日志被追加到文件结尾,如果是false表示清空文件 -->
        <append>${IS_APPEND}</append>
        <!--立即刷新,设置成false可以提高日志吞吐量-->
        <immediateFlush>${IS_IMMEDIATEFLUSH}</immediateFlush>
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <pattern>${FILE_LOG_PATTERN}</pattern>
            <charset>${ENCODING}</charset>
        </encoder>
    </appender>

    <!-- 将项目本次运行INFO日志异步输出到文件,会自动清空文件中上一次的日志 -->
    <appender name="ASYNC-APPENDER-FILEAPPENDER-INFO" class="ch.qos.logback.classic.AsyncAppender">
        <appender-ref ref="APPENDER-FILEAPPENDER-INFO" />
        <!-- 设置异步阻塞队列的大小,为了不丢失日志建议设置的大一些,单机压测时100000是没问题的,应该不用担心OOM -->
        <queueSize>10000</queueSize>
        <!-- 设置丢弃DEBUG、TRACE、INFO日志的阀值,不丢失 -->
        <discardingThreshold>0</discardingThreshold>
        <!-- 设置队列入队时非阻塞,当队列满时会直接丢弃日志,但是对性能提升极大 -->
        <neverBlock>${IS_IMMEDIATEFLUSH}</neverBlock>
    </appender>

    <!-- 将项目本次运行DEBUG日志同步输出到文件,会自动清空文件中上一次的日志 -->
    <appender name="APPENDER-FILEAPPENDER-DEBUG" class="ch.qos.logback.core.FileAppender">
        <!-- 过滤器,只记录 info 级别以上的日志 -->
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <level>DEBUG</level>
        </filter>
        <!-- 写入的日志文件名,可以使相对目录也可以是绝对目录,如果上级目录不存在则自动创建 -->
        <file>${LOG_PATH}/${MACHINE_IP}/${VIRTUAL_IP}/${LOG_NAME}-debug.log</file>
        <!-- 如果为true表示日志被追加到文件结尾,如果是false表示清空文件 -->
        <append>${IS_APPEND}</append>
        <!--立即刷新,设置成false可以提高日志吞吐量-->
        <immediateFlush>true</immediateFlush>
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <pattern>${FILE_LOG_PATTERN}</pattern>
            <charset>${ENCODING}</charset>
        </encoder>
    </appender>

    <!-- 将项目本次运行DEBUG日志异步输出到文件,会自动清空文件中上一次的日志 -->
    <appender name="ASYNC-APPENDER-FILEAPPENDER-DEBUG" class="ch.qos.logback.classic.AsyncAppender">
        <appender-ref ref="APPENDER-FILEAPPENDER-DEBUG" />
        <!-- 设置异步阻塞队列的大小,为了不丢失日志建议设置的大一些,单机压测时100000是没问题的,应该不用担心OOM -->
        <queueSize>10000</queueSize>
        <!-- 设置丢弃DEBUG、TRACE、INFO日志的阀值,不丢失 -->
        <discardingThreshold>0</discardingThreshold>
        <!-- 设置队列入队时非阻塞,当队列满时会直接丢弃日志,但是对性能提升极大 -->
        <neverBlock>true</neverBlock>
    </appender>

    <!-- 将项目本次运行ERROR日志同步输出到文件,会自动清空文件中上一次的日志 -->
    <appender name="APPENDER-FILEAPPENDER-ERROR" class="ch.qos.logback.core.FileAppender">
        <!-- 过滤器,只记录 info 级别以上的日志 -->
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <level>DEBUG</level>
        </filter>
        <!-- 写入的日志文件名,可以使相对目录也可以是绝对目录,如果上级目录不存在则自动创建 -->
        <file>${LOG_PATH}/${MACHINE_IP}/${VIRTUAL_IP}/${LOG_NAME}-error.log</file>
        <!-- 如果为true表示日志被追加到文件结尾,如果是false表示清空文件 -->
        <append>${IS_APPEND}</append>
        <!--立即刷新,设置成false可以提高日志吞吐量-->
        <immediateFlush>${IS_IMMEDIATEFLUSH}</immediateFlush>
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <pattern>${FILE_LOG_PATTERN}</pattern>
            <charset>${ENCODING}</charset>
        </encoder>
    </appender>

    <!-- 将项目本次运行ERROR日志异步输出到文件,会自动清空文件中上一次的日志 -->
    <appender name="ASYNC-APPENDER-FILEAPPENDER-ERROR" class="ch.qos.logback.classic.AsyncAppender">
        <appender-ref ref="APPENDER-FILEAPPENDER-ERROR" />
        <!-- 设置异步阻塞队列的大小,为了不丢失日志建议设置的大一些,单机压测时100000是没问题的,应该不用担心OOM -->
        <queueSize>10000</queueSize>
        <!-- 设置丢弃DEBUG、TRACE、INFO日志的阀值,不丢失 -->
        <discardingThreshold>0</discardingThreshold>
        <!-- 设置队列入队时非阻塞,当队列满时会直接丢弃日志,但是对性能提升极大 -->
        <neverBlock>true</neverBlock>
    </appender>
    <!--输出到文件:结束-->


    <!--滚动输出到文件(按照天保存):开始-->
    <!-- 将项目本次运行INFO日志同步输出到文件,按照每天生成日志文件,会自动拼接上一次日志 -->
    <appender name="APPENDER-ROLLINGFILEAPPENDER-INFO" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <!-- 过滤器,只记录 info 级别以上的日志 -->
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <level>INFO</level>
        </filter>
        <!--立即刷新,设置成false可以提高日志吞吐量-->
        <immediateFlush>false</immediateFlush>
        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
            <!-- 日志文件输出的文件名:
                %d:可以包含一个Java.text.SimpleDateFormat指定的时间格式
                %i:自增数字
            -->
            <fileNamePattern>${LOG_PATH}/${MACHINE_IP}/${VIRTUAL_IP}/HISTORY/${LOG_NAME}-info-%d{yyyy-MM-dd}-index%i.log</fileNamePattern>
            <!-- 日志文件保存历史数量:控制保留的归档文件的最大数量,如果超出数量就删除旧文件 -->
            <maxHistory>10</maxHistory>
            <!-- 文件大小超过100MB归档 -->
            <maxFileSize>20MB</maxFileSize>
        </rollingPolicy>
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <pattern>${FILE_LOG_PATTERN}</pattern>
            <charset>${ENCODING}</charset>
        </encoder>
    </appender>

    <!-- 将项目本次运行INFO日志异步输出到文件,按照每天生成日志文件,会自动拼接上一次日志 -->
    <appender name="ASYNC-APPENDER-ROLLINGFILEAPPENDER-INFO" class="ch.qos.logback.classic.AsyncAppender">
        <appender-ref ref="APPENDER-ROLLINGFILEAPPENDER-INFO" />
        <!-- 设置异步阻塞队列的大小,为了不丢失日志建议设置的大一些,单机压测时100000是没问题的,应该不用担心OOM -->
        <queueSize>10000</queueSize>
        <!-- 设置丢弃DEBUG、TRACE、INFO日志的阀值,不丢失 -->
        <discardingThreshold>0</discardingThreshold>
        <!-- 设置队列入队时非阻塞,当队列满时会直接丢弃日志,但是对性能提升极大 -->
        <neverBlock>true</neverBlock>
    </appender>

    <!-- 将项目本次运行DEBUG日志同步输出到文件,按照每天生成日志文件,会自动拼接上一次日志 -->
    <appender name="APPENDER-ROLLINGFILEAPPENDER-DEBUG" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <!-- 过滤器,只记录 info 级别以上的日志 -->
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <level>DEBUG</level>
        </filter>
        <!--立即刷新,设置成false可以提高日志吞吐量-->
        <immediateFlush>false</immediateFlush>
        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
            <!-- 日志文件输出的文件名:
                %d:可以包含一个Java.text.SimpleDateFormat指定的时间格式
                %i:自增数字
            -->
            <fileNamePattern>${LOG_PATH}/${MACHINE_IP}/${VIRTUAL_IP}/HISTORY/${LOG_NAME}-debug-%d{yyyy-MM-dd}-index%i.log</fileNamePattern>
            <!-- 日志文件保存历史数量:控制保留的归档文件的最大数量,如果超出数量就删除旧文件 -->
            <maxHistory>10</maxHistory>
            <!-- 文件大小超过100MB归档 -->
            <maxFileSize>20MB</maxFileSize>
        </rollingPolicy>
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <pattern>${FILE_LOG_PATTERN}</pattern>
            <charset>${ENCODING}</charset>
        </encoder>
    </appender>

    <!-- 将项目本次运行DEBUG日志异步输出到文件,按照每天生成日志文件,会自动拼接上一次日志 -->
    <appender name="ASYNC-APPENDER-ROLLINGFILEAPPENDER-DEBUG" class="ch.qos.logback.classic.AsyncAppender">
        <appender-ref ref="APPENDER-ROLLINGFILEAPPENDER-DEBUG" />
        <!-- 设置异步阻塞队列的大小,为了不丢失日志建议设置的大一些,单机压测时100000是没问题的,应该不用担心OOM -->
        <queueSize>10000</queueSize>
        <!-- 设置丢弃DEBUG、TRACE、INFO日志的阀值,不丢失 -->
        <discardingThreshold>0</discardingThreshold>
        <!-- 设置队列入队时非阻塞,当队列满时会直接丢弃日志,但是对性能提升极大 -->
        <neverBlock>true</neverBlock>
    </appender>

    <!-- 将项目本次运行ERROR日志同步输出到文件,按照每天生成日志文件,会自动拼接上一次日志 -->
    <appender name="APPENDER-ROLLINGFILEAPPENDER-ERROR" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <!-- 过滤器,只记录error级别的日志 -->
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>ERROR</level>
            <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>
        <!--立即刷新,设置成false可以提高日志吞吐量-->
        <immediateFlush>false</immediateFlush>
        <!-- 每天生成一个日志文件,保存30天的日志文件 -->
        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
            <!-- 日志文件输出的文件名:按天回滚 daily -->
            <fileNamePattern>${LOG_PATH}/${MACHINE_IP}/${VIRTUAL_IP}/HISTORY/${LOG_NAME}-error-%d{yyyy-MM-dd}-index%i.log</fileNamePattern>
            <!-- 日志文件保留天数 -->
            <maxHistory>10</maxHistory>
            <!-- 文件大小超过100MB归档 -->
            <maxFileSize>20MB</maxFileSize>
        </rollingPolicy>
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <pattern>${FILE_LOG_PATTERN}</pattern>
            <charset>utf8</charset>
        </encoder>
    </appender>

    <appender name="ASYNC-APPENDER-ROLLINGFILEAPPENDER-ERROR" class="ch.qos.logback.classic.AsyncAppender">
        <appender-ref ref="APPENDER-ROLLINGFILEAPPENDER-ERROR" />
        <!-- 设置异步阻塞队列的大小,为了不丢失日志建议设置的大一些,单机压测时100000是没问题的,应该不用担心OOM -->
        <queueSize>10000</queueSize>
        <!-- 设置丢弃DEBUG、TRACE、INFO日志的阀值,不丢失 -->
        <discardingThreshold>0</discardingThreshold>
        <!-- 设置队列入队时非阻塞,当队列满时会直接丢弃日志,但是对性能提升极大 -->
        <neverBlock>true</neverBlock>
    </appender>
    <!--滚动输出到文件(按照天保存):结束-->

    <!--输出到LOGSTASH:开始-->
    <!-- 将项目本次运行ERROR日志同步输出到文件,按照每天生成日志文件,会自动拼接上一次日志 -->
    <appender name="APPENDER-LOGSTASH" class="net.logstash.logback.appender.LogstashTcpSocketAppender">
        <!--  logstash服务器地址-->
        <destination>${LOGSTASH_HOST}</destination>
        <encoder class="net.logstash.logback.encoder.LoggingEventCompositeJsonEncoder">
            <providers>
                <pattern>
                    <pattern>
                        {
                        "appName":"${INDEX_NAME}",
                        "machineIp":"${MACHINE_IP}",
                        "virtualIp":"${VIRTUAL_IP}",
                        "serviceName":"${LOG_NAME}",
                        "timestamp": "%date{\"yyyy-MM-dd'T'HH:mm:ss,SSSZ\"}",
                        "logLevel":"%level",
                        "message":"%msg%n",
                        "traceId": "%X{X-B3-TraceId:-}",
                        "spanId": "%X{X-B3-SpanId:-}",
                        "spanExport": "%X{X-Span-Export:-}"
                        }
                    </pattern>
                </pattern>
            </providers>
        </encoder>
    </appender>
    <appender name="ASYNC-APPENDER-LOGSTASH" class="ch.qos.logback.classic.AsyncAppender">
        <appender-ref ref="APPENDER-LOGSTASH" />
        <!-- 设置异步阻塞队列的大小,为了不丢失日志建议设置的大一些,单机压测时100000是没问题的,应该不用担心OOM -->
        <queueSize>10000</queueSize>
        <!-- 设置丢弃DEBUG、TRACE、INFO日志的阀值,不丢失 -->
        <discardingThreshold>0</discardingThreshold>
        <!-- 设置队列入队时非阻塞,当队列满时会直接丢弃日志,但是对性能提升极大 -->
        <neverBlock>true</neverBlock>
    </appender>
    <!--输出到logstash:结束-->

    <!--
        开发环境日志级别为DEBUG
        level:用来设置打印级别
        五个常用打印级别从低至高依次为TRACE、DEBUG、INFO、WARN、ERROR
    -->
    <springProfile name="dev">
        <root>
            <!--输出到控制台-->
            <appender-ref ref="STDOUT"/>
            <!--异步非滚动输出到文件-->
            <appender-ref ref="ASYNC-APPENDER-FILEAPPENDER-INFO"/>
            <appender-ref ref="ASYNC-APPENDER-FILEAPPENDER-DEBUG"/>
            <appender-ref ref="ASYNC-APPENDER-FILEAPPENDER-ERROR"/>
            <!--异步滚动输出到文件:dev环境不开启-->
<!--            <appender-ref ref="ASYNC-APPENDER-ROLLINGFILEAPPENDER-INFO"/>-->
<!--            <appender-ref ref="ASYNC-APPENDER-ROLLINGFILEAPPENDER-DEBUG"/>-->
<!--            <appender-ref ref="ASYNC-APPENDER-ROLLINGFILEAPPENDER-ERROR"/>-->
            <!--异步滚动输出到logstash-->
            <appender-ref ref="ASYNC-APPENDER-LOGSTASH"/>
        </root>
    </springProfile>

    <!-- 测试环境日志级别为INFO -->
    <springProfile name="test">
        <root>
            <!--输出到控制台-->
            <appender-ref ref="STDOUT"/>
            <!--异步非滚动输出到文件-->
            <appender-ref ref="ASYNC-APPENDER-FILEAPPENDER-INFO"/>
            <appender-ref ref="ASYNC-APPENDER-FILEAPPENDER-DEBUG"/>
            <appender-ref ref="ASYNC-APPENDER-FILEAPPENDER-ERROR"/>
            <!--异步滚动输出到文件:test环境不开启-->
<!--            <appender-ref ref="ASYNC-APPENDER-ROLLINGFILEAPPENDER-INFO"/>-->
<!--            <appender-ref ref="ASYNC-APPENDER-ROLLINGFILEAPPENDER-DEBUG"/>-->
<!--            <appender-ref ref="ASYNC-APPENDER-ROLLINGFILEAPPENDER-ERROR"/>-->
            <!--异步滚动输出到logstash-->
            <appender-ref ref="ASYNC-APPENDER-LOGSTASH"/>
        </root>
    </springProfile>

    <!-- 生产环境日志级别为INFO -->
    <springProfile name="prod">
        <root>
            <!--输出到控制台-->
            <appender-ref ref="STDOUT"/>
            <!--异步非滚动输出到文件-->
            <appender-ref ref="ASYNC-APPENDER-FILEAPPENDER-INFO"/>
            <appender-ref ref="ASYNC-APPENDER-FILEAPPENDER-DEBUG"/>
            <appender-ref ref="ASYNC-APPENDER-FILEAPPENDER-ERROR"/>
            <!--异步滚动输出到文件-->
            <appender-ref ref="ASYNC-APPENDER-ROLLINGFILEAPPENDER-INFO"/>
            <appender-ref ref="ASYNC-APPENDER-ROLLINGFILEAPPENDER-DEBUG"/>
            <appender-ref ref="ASYNC-APPENDER-ROLLINGFILEAPPENDER-ERROR"/>
            <!--异步滚动输出到logstash-->
            <appender-ref ref="ASYNC-APPENDER-LOGSTASH"/>
        </root>
    </springProfile>

    <!-- rancher环境日志级别为INFO -->
    <springProfile name="rancher">
        <root>
            <!--输出到控制台-->
            <appender-ref ref="STDOUT"/>
            <!--异步非滚动输出到文件-->
            <appender-ref ref="ASYNC-APPENDER-FILEAPPENDER-INFO"/>
            <appender-ref ref="ASYNC-APPENDER-FILEAPPENDER-DEBUG"/>
            <appender-ref ref="ASYNC-APPENDER-FILEAPPENDER-ERROR"/>
            <!--异步滚动输出到文件-->
            <appender-ref ref="ASYNC-APPENDER-ROLLINGFILEAPPENDER-INFO"/>
            <appender-ref ref="ASYNC-APPENDER-ROLLINGFILEAPPENDER-DEBUG"/>
            <appender-ref ref="ASYNC-APPENDER-ROLLINGFILEAPPENDER-ERROR"/>
            <!--异步滚动输出到logstash-->
            <appender-ref ref="ASYNC-APPENDER-LOGSTASH"/>
        </root>
    </springProfile>
</configuration>

PaymentMapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >

<mapper namespace="org.openatom.springcloud.dao.PaymentDao">

    <!--第一种写法:parameterType不写全路径-->
    <insert id="create" parameterType="Payment" useGeneratedKeys="true" keyProperty="id">
        insert into payment(serial)  values(#{serial});
    </insert>

    <resultMap id="BaseResultMap" type="Payment">
        <id column="id" property="id" jdbcType="BIGINT"/>
        <id column="serial" property="serial" jdbcType="VARCHAR"/>
    </resultMap>
    <select id="getPaymentById" parameterType="Long" resultMap="BaseResultMap">
        select * from payment where id=#{id};
    </select>

    <!--第二种写法:parameterType的写法与第一种有区别-->
    <!--
    <insert id="create" parameterType="org.openatom.springcloud.entities.Payment" useGeneratedKeys="true" keyProperty="id">
        insert into payment(serial)  values(#{serial});
    </insert>

    <resultMap id="BaseResultMap" type="org.openatom.springcloud.entities.Payment">
        <id column="id" property="id" jdbcType="BIGINT"/>
        <id column="serial" property="serial" jdbcType="VARCHAR"/>
    </resultMap>
    <select id="getPaymentById" parameterType="Long" resultMap="BaseResultMap">
        select * from payment where id=#{id};
    </select>
    -->
</mapper>



rancher环境配置文件
application.yml
#设置spring项目运行的环境
spring:
  profiles:
    active: '@profile.active@'


application-rancher.yml
server:
  port: 8010 #访问端口
spring:
  application:
    name: SPRINGCLOUD-BASIC-SAMPLE-PROVIDER-PAYMENT-SERVICE-CLUSTER-RANCHER  #注意:服务名不要出现_
  devtools:
    restart:
      enabled: true
  # 将Client作为服务注册到SpringBootAdmin Server端,通过Server来监听项目的运行情况
  boot:
    admin:
      client:
        url: http://192.168.0.4:${server.port}
  logging:
    level: info
  datasource:
    type: com.alibaba.druid.pool.DruidDataSource            # 当前数据源操作类型
    driver-class-name: com.mysql.cj.jdbc.Driver              # mysql驱动包
    #192.168.0.2:docker容器外部数据库环境,192.168.0.4:docker容器内部数据库环境
    url: jdbc:mysql://192.168.0.4:3306/payment?useUnicode=true&characterEncoding=utf-8&useSSL=false&allowPublicKeyRetrieval=true
    username: root
    password: 123456

eureka:
  client:
    register-with-eureka: true  #表示是否将自己注册进EurekaServer默认为true。
    fetchRegistry: true  #是否从EurekaServer抓取已有的注册信息,默认为true。单节点无所谓,集群必须设置为true才能配合ribbon使用负载均衡
    service-url:
      #单机版
      defaultZone: http://192.168.0.4:7005/eureka
      #集群版
      #defaultZone: http://eureka7002:7002/eureka,http://eureka7003:7003/eureka,http://eureka7004:7004/eureka
  instance:
    #使用rancher扩容不能配置instance-id,否则会出问题
    #instance-id: SPRINGCLOUD-PROVIDER-PAYMENT-SERVICE-CLUSTER-NODE-PAYMENT8010-PROD #Eureka仪表盘中Instances currently registered with Eureka.Status显示的内容
    #使用rancher扩容不能配置iip-address,否则会出问题
    #ip-address: 192.168.0.4
    prefer-ip-address: true  #访问路径可以显示IP地址,点击Eureka仪表盘中Instances currently registered with Eureka.Status显示的内容地址栏是否显示IP地址
    lease-renewal-interval-in-seconds: 30 #Eureka客户端向服务端发送心跳的时间间隔,单位为秒(默认是30秒)
    lease-expiration-duration-in-seconds: 90 #Eureka服务端在收到最后一次心跳后等待时间上限,单位为秒(默认是90秒),超时将剔除服务

mybatis:
  mapperLocations: classpath:mapper/*.xml
  type-aliases-package: org.openatom.springcloud.entities    # 所有Entity别名类所在包

#配置文件修改说明-------------------------------------------------:开始
#注意:不同的部署环境需要修改的配置
#   1.${logback.path}  #修改日志存放位置,Linxu为/,Windows为\
#       修改原因: Linux和Windows目录结构不同
#   2.${logback.deploy-machine-ip}  #修改项目部署机器所在ip,方便收集日志
#配置文件修改说明-------------------------------------------------:结束

#自定义日志配置文件路径
logging:
  config: classpath:logback-custom.xml
  path: /logs #所有日志存放在位置,加上\方便Linux环境下配置
  level:
    root: info #全局日志输出级别

logback:
  log-name: ${spring.application.name}
  append: false #是否启用append(追加到已经存在日志文件尾部),true:重启项目会追加新日志到之前日志,false:重启项目会清空之前的日志
  immediate-flush: true #是否启用immediateFlush(立即刷新),true:重启项目自动追加,false:重启项目会情况之前的日志
  deploy-machine-ip: 192.168.0.4 #当前微服务所在部署机器ip

#logstash相关配置:开始
logstash:
  host: 192.168.0.4:5044 # logstash地址
  index: '@project.parent.artifactId@' # es中index名称
#logstash相关配置:结束

#actuator监控:开始
#通过下面的配置启用所有的监控端点,默认情况下,这些端点是禁用的;
management:
  endpoints:
    web:
      exposure:
        include: '*'
    enabled-by-default: true
  endpoint:
    health:
      show-details: always # 访问/actuator/health时,显示详细信息,而不是仅仅显示"status": "UP"
    # 日志文件路径:特别注意,此处无法配置日志文件路径,因为rancher会生成虚拟ip,这个虚拟ip是无法在这里获取的,
    #           但是虚拟ip是路径的一部分,所以这个路径无法拼接出来,所以这里无法配置日志文件路径
    #logfile:
    #  external-file:
#actuator监控:结束

logback-custom.xml
<?xml version="1.0" encoding="UTF-8"?>

<!--
    scan: 当此属性设置为true时,配置文件如果发生改变,将会被重新加载,默认值为true。
    scanPeriod: 设置监测配置文件是否有修改的时间间隔,如果没有给出时间单位,默认单位是毫秒。当scan为true时,此属性生效。默认的时间间隔为1分钟。
    debug: 当此属性设置为true时,将打印出logback内部日志信息,实时查看logback运行状态。默认值为false。
-->
<!-- 输出logback内部日志信息,每隔30s判断一下配置文件有没有更新,若更新,则重新加载 -->
<configuration scan="true" scanPeriod="30 seconds" debug="false">
    <!--从java代码中获取虚拟ip的值-->
    <!--获取当前微服务部署虚拟IP,如rancher为当前微服务分配的ip-->
    <define name="VIRTUAL_IP" class="org.openatom.springcloud.config.VirtualIpConfig"/>

    <!--从Spring容器中获取配置(Spring配置文件加载顺序:bootstrap.yml->logback.xml->application.yml)-->
    <!--获取当前微服务部署机器ip-->
    <springProperty name="MACHINE_IP" scope="context" source="logback.deploy-machine-ip"/>
    <!--应用名称-->
    <springProperty name="LOG_NAME" scope="context" source="logback.log-name"/>
    <!--是否启用append-->
    <springProperty name="IS_APPEND" scope="context" source="logback.append"/>
    <!--是否启用立即刷新-->
    <springProperty name="IS_IMMEDIATEFLUSH" scope="context" source="logback.immediate-flush"/>
    <springProperty name="LOG_PATH" scope="context" source="logging.path"/>
    <!--logstash地址-->
    <springProperty name="LOGSTASH_HOST" scope="context" source="logstash.host"/>
    <!--索引名称-->
    <springProperty name="INDEX_NAME" scope="context" source="logstash.index"/>


    <!-- name:变量的名称,可以随意起名,但建议名字要简明直译;value:变量的值;在配置文件中,我们可以用 ${} 的方式来使用,将变量引入到其他节点中去。-->
    <!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度 %msg:日志消息,%n是换行符-->
    <!--控制台日志输出预选样式-->
    <property name="CONSOLE_LOG_PATTERN_1" value="%red(%d{yyyy-MM-dd HH:mm:ss.SSS}) %green([%thread]) [machineIp:${MACHINE_IP} virtualIp:${VIRTUAL_IP}] [TraceId:%X{X-B3-TraceId:-} SpanId:%X{X-B3-SpanId:-} %highlight(%-5level) %boldMagenta(%logger{10}): %cyan(%msg%n)"/>
    <property name="CONSOLE_LOG_PATTERN_2" value="%yellow(%date{yyyy-MM-dd HH:mm:ss}) [machineIp:${MACHINE_IP} virtualIp:${VIRTUAL_IP}] [TraceId:%X{X-B3-TraceId:-} SpanId:%X{X-B3-SpanId:-} %highlight([%-5level]) %green(%logger) %msg%n"/>
    <property name="CONSOLE_LOG_PATTERN_3" value="%date{yyyy-MM-dd HH:mm:ss} [machineIp:${MACHINE_IP} virtualIp:${VIRTUAL_IP}] [TraceId:%X{X-B3-TraceId:-} SpanId:%X{X-B3-SpanId:-} Span-Export:%X{X-Span-Export:-}]  %green(%-5level) %boldMagenta(${PID:-}) -- [%+20thread] %cyan(%logger{20}) %line       : %msg%n"/>
    <!--文件中日志输出预选样式-->
    <property name="FILE_LOG_PATTERN_1" value="%d{yyyyMMdd:HH:mm:ss.SSS} [machineIp:${MACHINE_IP} virtualIp:${VIRTUAL_IP}] [TraceId:%X{X-B3-TraceId:-} SpanId:%X{X-B3-SpanId:-} [%thread] %-5level  %msg%n"/>

    <!--控制台日志输出格式-->
    <property name="CONSOLE_LOG_PATTERN" value="${CONSOLE_LOG_PATTERN_3}"/>
    <!--文件中日志输出格式-->
    <property name="FILE_LOG_PATTERN" value="${FILE_LOG_PATTERN_1}"/>
    <!--日志名称-->
    <!--定义默认日志输出级别-->
    <property name="LOG_OUTPUT_LEVEL" value="${LOG_LEVEL}" />
    <!--定义默认日志输出编码-->
    <property name="ENCODING" value="UTF-8" />

    <!-- 控制台输出:开始 -->
    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
        <!-- 用来设置日志的输入格式,使用“%+转换符”的方式,如果要输出”%”则必须使用”\”进行转义。-->
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <!-- 格式化输出:https://logback.qos.ch/manual/layouts.html
                 %d 表示日期,
                 %thread 表示线程名,
                 %level 日志级别从左显示5个字符宽度,
                 %t 线程名
                 %file:%line 文件名+行号,
                 %m 日志消息,%n是换行符
                 %X{traceId}:自定义设置的参数,后面会说。
            -->
            <pattern>${CONSOLE_LOG_PATTERN}</pattern>
            <charset>${ENCODING}</charset>
        </encoder>
    </appender>
    <!-- 控制台输出:结束 -->

    <!--输出到文件:开始-->
    <!-- 将项目本次运行INFO日志同步输出到文件,会自动清空文件中上一次的日志 -->
    <appender name="APPENDER-FILEAPPENDER-INFO" class="ch.qos.logback.core.FileAppender">
        <!-- 过滤器,只记录 info 级别以上的日志 -->
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <level>INFO</level>
        </filter>
        <!-- 写入的日志文件名,可以使相对目录也可以是绝对目录,如果上级目录不存在则自动创建 -->
        <file>${LOG_PATH}/${MACHINE_IP}/${VIRTUAL_IP}/${LOG_NAME}-info.log</file>
        <!-- 如果为true表示日志被追加到文件结尾,如果是false表示清空文件 -->
        <append>${IS_APPEND}</append>
        <!--立即刷新,设置成false可以提高日志吞吐量-->
        <immediateFlush>${IS_IMMEDIATEFLUSH}</immediateFlush>
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <pattern>${FILE_LOG_PATTERN}</pattern>
            <charset>${ENCODING}</charset>
        </encoder>
    </appender>

    <!-- 将项目本次运行INFO日志异步输出到文件,会自动清空文件中上一次的日志 -->
    <appender name="ASYNC-APPENDER-FILEAPPENDER-INFO" class="ch.qos.logback.classic.AsyncAppender">
        <appender-ref ref="APPENDER-FILEAPPENDER-INFO" />
        <!-- 设置异步阻塞队列的大小,为了不丢失日志建议设置的大一些,单机压测时100000是没问题的,应该不用担心OOM -->
        <queueSize>10000</queueSize>
        <!-- 设置丢弃DEBUG、TRACE、INFO日志的阀值,不丢失 -->
        <discardingThreshold>0</discardingThreshold>
        <!-- 设置队列入队时非阻塞,当队列满时会直接丢弃日志,但是对性能提升极大 -->
        <neverBlock>${IS_IMMEDIATEFLUSH}</neverBlock>
    </appender>

    <!-- 将项目本次运行DEBUG日志同步输出到文件,会自动清空文件中上一次的日志 -->
    <appender name="APPENDER-FILEAPPENDER-DEBUG" class="ch.qos.logback.core.FileAppender">
        <!-- 过滤器,只记录 info 级别以上的日志 -->
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <level>DEBUG</level>
        </filter>
        <!-- 写入的日志文件名,可以使相对目录也可以是绝对目录,如果上级目录不存在则自动创建 -->
        <file>${LOG_PATH}/${MACHINE_IP}/${VIRTUAL_IP}/${LOG_NAME}-debug.log</file>
        <!-- 如果为true表示日志被追加到文件结尾,如果是false表示清空文件 -->
        <append>${IS_APPEND}</append>
        <!--立即刷新,设置成false可以提高日志吞吐量-->
        <immediateFlush>true</immediateFlush>
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <pattern>${FILE_LOG_PATTERN}</pattern>
            <charset>${ENCODING}</charset>
        </encoder>
    </appender>

    <!-- 将项目本次运行DEBUG日志异步输出到文件,会自动清空文件中上一次的日志 -->
    <appender name="ASYNC-APPENDER-FILEAPPENDER-DEBUG" class="ch.qos.logback.classic.AsyncAppender">
        <appender-ref ref="APPENDER-FILEAPPENDER-DEBUG" />
        <!-- 设置异步阻塞队列的大小,为了不丢失日志建议设置的大一些,单机压测时100000是没问题的,应该不用担心OOM -->
        <queueSize>10000</queueSize>
        <!-- 设置丢弃DEBUG、TRACE、INFO日志的阀值,不丢失 -->
        <discardingThreshold>0</discardingThreshold>
        <!-- 设置队列入队时非阻塞,当队列满时会直接丢弃日志,但是对性能提升极大 -->
        <neverBlock>true</neverBlock>
    </appender>

    <!-- 将项目本次运行ERROR日志同步输出到文件,会自动清空文件中上一次的日志 -->
    <appender name="APPENDER-FILEAPPENDER-ERROR" class="ch.qos.logback.core.FileAppender">
        <!-- 过滤器,只记录 info 级别以上的日志 -->
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <level>DEBUG</level>
        </filter>
        <!-- 写入的日志文件名,可以使相对目录也可以是绝对目录,如果上级目录不存在则自动创建 -->
        <file>${LOG_PATH}/${MACHINE_IP}/${VIRTUAL_IP}/${LOG_NAME}-error.log</file>
        <!-- 如果为true表示日志被追加到文件结尾,如果是false表示清空文件 -->
        <append>${IS_APPEND}</append>
        <!--立即刷新,设置成false可以提高日志吞吐量-->
        <immediateFlush>${IS_IMMEDIATEFLUSH}</immediateFlush>
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <pattern>${FILE_LOG_PATTERN}</pattern>
            <charset>${ENCODING}</charset>
        </encoder>
    </appender>

    <!-- 将项目本次运行ERROR日志异步输出到文件,会自动清空文件中上一次的日志 -->
    <appender name="ASYNC-APPENDER-FILEAPPENDER-ERROR" class="ch.qos.logback.classic.AsyncAppender">
        <appender-ref ref="APPENDER-FILEAPPENDER-ERROR" />
        <!-- 设置异步阻塞队列的大小,为了不丢失日志建议设置的大一些,单机压测时100000是没问题的,应该不用担心OOM -->
        <queueSize>10000</queueSize>
        <!-- 设置丢弃DEBUG、TRACE、INFO日志的阀值,不丢失 -->
        <discardingThreshold>0</discardingThreshold>
        <!-- 设置队列入队时非阻塞,当队列满时会直接丢弃日志,但是对性能提升极大 -->
        <neverBlock>true</neverBlock>
    </appender>
    <!--输出到文件:结束-->


    <!--滚动输出到文件(按照天保存):开始-->
    <!-- 将项目本次运行INFO日志同步输出到文件,按照每天生成日志文件,会自动拼接上一次日志 -->
    <appender name="APPENDER-ROLLINGFILEAPPENDER-INFO" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <!-- 过滤器,只记录 info 级别以上的日志 -->
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <level>INFO</level>
        </filter>
        <!--立即刷新,设置成false可以提高日志吞吐量-->
        <immediateFlush>false</immediateFlush>
        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
            <!-- 日志文件输出的文件名:
                %d:可以包含一个Java.text.SimpleDateFormat指定的时间格式
                %i:自增数字
            -->
            <fileNamePattern>${LOG_PATH}/${MACHINE_IP}/${VIRTUAL_IP}/HISTORY/${LOG_NAME}-info-%d{yyyy-MM-dd}-index%i.log</fileNamePattern>
            <!-- 日志文件保存历史数量:控制保留的归档文件的最大数量,如果超出数量就删除旧文件 -->
            <maxHistory>10</maxHistory>
            <!-- 文件大小超过100MB归档 -->
            <maxFileSize>20MB</maxFileSize>
        </rollingPolicy>
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <pattern>${FILE_LOG_PATTERN}</pattern>
            <charset>${ENCODING}</charset>
        </encoder>
    </appender>

    <!-- 将项目本次运行INFO日志异步输出到文件,按照每天生成日志文件,会自动拼接上一次日志 -->
    <appender name="ASYNC-APPENDER-ROLLINGFILEAPPENDER-INFO" class="ch.qos.logback.classic.AsyncAppender">
        <appender-ref ref="APPENDER-ROLLINGFILEAPPENDER-INFO" />
        <!-- 设置异步阻塞队列的大小,为了不丢失日志建议设置的大一些,单机压测时100000是没问题的,应该不用担心OOM -->
        <queueSize>10000</queueSize>
        <!-- 设置丢弃DEBUG、TRACE、INFO日志的阀值,不丢失 -->
        <discardingThreshold>0</discardingThreshold>
        <!-- 设置队列入队时非阻塞,当队列满时会直接丢弃日志,但是对性能提升极大 -->
        <neverBlock>true</neverBlock>
    </appender>

    <!-- 将项目本次运行DEBUG日志同步输出到文件,按照每天生成日志文件,会自动拼接上一次日志 -->
    <appender name="APPENDER-ROLLINGFILEAPPENDER-DEBUG" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <!-- 过滤器,只记录 info 级别以上的日志 -->
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <level>DEBUG</level>
        </filter>
        <!--立即刷新,设置成false可以提高日志吞吐量-->
        <immediateFlush>false</immediateFlush>
        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
            <!-- 日志文件输出的文件名:
                %d:可以包含一个Java.text.SimpleDateFormat指定的时间格式
                %i:自增数字
            -->
            <fileNamePattern>${LOG_PATH}/${MACHINE_IP}/${VIRTUAL_IP}/HISTORY/${LOG_NAME}-debug-%d{yyyy-MM-dd}-index%i.log</fileNamePattern>
            <!-- 日志文件保存历史数量:控制保留的归档文件的最大数量,如果超出数量就删除旧文件 -->
            <maxHistory>10</maxHistory>
            <!-- 文件大小超过100MB归档 -->
            <maxFileSize>20MB</maxFileSize>
        </rollingPolicy>
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <pattern>${FILE_LOG_PATTERN}</pattern>
            <charset>${ENCODING}</charset>
        </encoder>
    </appender>

    <!-- 将项目本次运行DEBUG日志异步输出到文件,按照每天生成日志文件,会自动拼接上一次日志 -->
    <appender name="ASYNC-APPENDER-ROLLINGFILEAPPENDER-DEBUG" class="ch.qos.logback.classic.AsyncAppender">
        <appender-ref ref="APPENDER-ROLLINGFILEAPPENDER-DEBUG" />
        <!-- 设置异步阻塞队列的大小,为了不丢失日志建议设置的大一些,单机压测时100000是没问题的,应该不用担心OOM -->
        <queueSize>10000</queueSize>
        <!-- 设置丢弃DEBUG、TRACE、INFO日志的阀值,不丢失 -->
        <discardingThreshold>0</discardingThreshold>
        <!-- 设置队列入队时非阻塞,当队列满时会直接丢弃日志,但是对性能提升极大 -->
        <neverBlock>true</neverBlock>
    </appender>

    <!-- 将项目本次运行ERROR日志同步输出到文件,按照每天生成日志文件,会自动拼接上一次日志 -->
    <appender name="APPENDER-ROLLINGFILEAPPENDER-ERROR" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <!-- 过滤器,只记录error级别的日志 -->
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>ERROR</level>
            <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>
        <!--立即刷新,设置成false可以提高日志吞吐量-->
        <immediateFlush>false</immediateFlush>
        <!-- 每天生成一个日志文件,保存30天的日志文件 -->
        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
            <!-- 日志文件输出的文件名:按天回滚 daily -->
            <fileNamePattern>${LOG_PATH}/${MACHINE_IP}/${VIRTUAL_IP}/HISTORY/${LOG_NAME}-error-%d{yyyy-MM-dd}-index%i.log</fileNamePattern>
            <!-- 日志文件保留天数 -->
            <maxHistory>10</maxHistory>
            <!-- 文件大小超过100MB归档 -->
            <maxFileSize>20MB</maxFileSize>
        </rollingPolicy>
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <pattern>${FILE_LOG_PATTERN}</pattern>
            <charset>utf8</charset>
        </encoder>
    </appender>

    <appender name="ASYNC-APPENDER-ROLLINGFILEAPPENDER-ERROR" class="ch.qos.logback.classic.AsyncAppender">
        <appender-ref ref="APPENDER-ROLLINGFILEAPPENDER-ERROR" />
        <!-- 设置异步阻塞队列的大小,为了不丢失日志建议设置的大一些,单机压测时100000是没问题的,应该不用担心OOM -->
        <queueSize>10000</queueSize>
        <!-- 设置丢弃DEBUG、TRACE、INFO日志的阀值,不丢失 -->
        <discardingThreshold>0</discardingThreshold>
        <!-- 设置队列入队时非阻塞,当队列满时会直接丢弃日志,但是对性能提升极大 -->
        <neverBlock>true</neverBlock>
    </appender>
    <!--滚动输出到文件(按照天保存):结束-->

    <!--输出到LOGSTASH:开始-->
    <!-- 将项目本次运行ERROR日志同步输出到文件,按照每天生成日志文件,会自动拼接上一次日志 -->
    <appender name="APPENDER-LOGSTASH" class="net.logstash.logback.appender.LogstashTcpSocketAppender">
        <!--  logstash服务器地址-->
        <destination>${LOGSTASH_HOST}</destination>
        <encoder class="net.logstash.logback.encoder.LoggingEventCompositeJsonEncoder">
            <providers>
                <pattern>
                    <pattern>
                        {
                        "appName":"${INDEX_NAME}",
                        "machineIp":"${MACHINE_IP}",
                        "virtualIp":"${VIRTUAL_IP}",
                        "serviceName":"${LOG_NAME}",
                        "timestamp": "%date{\"yyyy-MM-dd'T'HH:mm:ss,SSSZ\"}",
                        "logLevel":"%level",
                        "message":"%msg%n",
                        "traceId": "%X{X-B3-TraceId:-}",
                        "spanId": "%X{X-B3-SpanId:-}",
                        "spanExport": "%X{X-Span-Export:-}"
                        }
                    </pattern>
                </pattern>
            </providers>
        </encoder>
    </appender>
    <appender name="ASYNC-APPENDER-LOGSTASH" class="ch.qos.logback.classic.AsyncAppender">
        <appender-ref ref="APPENDER-LOGSTASH" />
        <!-- 设置异步阻塞队列的大小,为了不丢失日志建议设置的大一些,单机压测时100000是没问题的,应该不用担心OOM -->
        <queueSize>10000</queueSize>
        <!-- 设置丢弃DEBUG、TRACE、INFO日志的阀值,不丢失 -->
        <discardingThreshold>0</discardingThreshold>
        <!-- 设置队列入队时非阻塞,当队列满时会直接丢弃日志,但是对性能提升极大 -->
        <neverBlock>true</neverBlock>
    </appender>
    <!--输出到logstash:结束-->

    <!--
        开发环境日志级别为DEBUG
        level:用来设置打印级别
        五个常用打印级别从低至高依次为TRACE、DEBUG、INFO、WARN、ERROR
    -->
    <springProfile name="dev">
        <root>
            <!--输出到控制台-->
            <appender-ref ref="STDOUT"/>
            <!--异步非滚动输出到文件-->
            <appender-ref ref="ASYNC-APPENDER-FILEAPPENDER-INFO"/>
            <appender-ref ref="ASYNC-APPENDER-FILEAPPENDER-DEBUG"/>
            <appender-ref ref="ASYNC-APPENDER-FILEAPPENDER-ERROR"/>
            <!--异步滚动输出到文件:dev环境不开启-->
<!--            <appender-ref ref="ASYNC-APPENDER-ROLLINGFILEAPPENDER-INFO"/>-->
<!--            <appender-ref ref="ASYNC-APPENDER-ROLLINGFILEAPPENDER-DEBUG"/>-->
<!--            <appender-ref ref="ASYNC-APPENDER-ROLLINGFILEAPPENDER-ERROR"/>-->
            <!--异步滚动输出到logstash-->
            <appender-ref ref="ASYNC-APPENDER-LOGSTASH"/>
        </root>
    </springProfile>

    <!-- 测试环境日志级别为INFO -->
    <springProfile name="test">
        <root>
            <!--输出到控制台-->
            <appender-ref ref="STDOUT"/>
            <!--异步非滚动输出到文件-->
            <appender-ref ref="ASYNC-APPENDER-FILEAPPENDER-INFO"/>
            <appender-ref ref="ASYNC-APPENDER-FILEAPPENDER-DEBUG"/>
            <appender-ref ref="ASYNC-APPENDER-FILEAPPENDER-ERROR"/>
            <!--异步滚动输出到文件:test环境不开启-->
<!--            <appender-ref ref="ASYNC-APPENDER-ROLLINGFILEAPPENDER-INFO"/>-->
<!--            <appender-ref ref="ASYNC-APPENDER-ROLLINGFILEAPPENDER-DEBUG"/>-->
<!--            <appender-ref ref="ASYNC-APPENDER-ROLLINGFILEAPPENDER-ERROR"/>-->
            <!--异步滚动输出到logstash-->
            <appender-ref ref="ASYNC-APPENDER-LOGSTASH"/>
        </root>
    </springProfile>

    <!-- 生产环境日志级别为INFO -->
    <springProfile name="prod">
        <root>
            <!--输出到控制台-->
            <appender-ref ref="STDOUT"/>
            <!--异步非滚动输出到文件-->
            <appender-ref ref="ASYNC-APPENDER-FILEAPPENDER-INFO"/>
            <appender-ref ref="ASYNC-APPENDER-FILEAPPENDER-DEBUG"/>
            <appender-ref ref="ASYNC-APPENDER-FILEAPPENDER-ERROR"/>
            <!--异步滚动输出到文件-->
            <appender-ref ref="ASYNC-APPENDER-ROLLINGFILEAPPENDER-INFO"/>
            <appender-ref ref="ASYNC-APPENDER-ROLLINGFILEAPPENDER-DEBUG"/>
            <appender-ref ref="ASYNC-APPENDER-ROLLINGFILEAPPENDER-ERROR"/>
            <!--异步滚动输出到logstash-->
            <appender-ref ref="ASYNC-APPENDER-LOGSTASH"/>
        </root>
    </springProfile>

    <!-- rancher环境日志级别为INFO -->
    <springProfile name="rancher">
        <root>
            <!--输出到控制台-->
            <appender-ref ref="STDOUT"/>
            <!--异步非滚动输出到文件-->
            <appender-ref ref="ASYNC-APPENDER-FILEAPPENDER-INFO"/>
            <appender-ref ref="ASYNC-APPENDER-FILEAPPENDER-DEBUG"/>
            <appender-ref ref="ASYNC-APPENDER-FILEAPPENDER-ERROR"/>
            <!--异步滚动输出到文件-->
            <appender-ref ref="ASYNC-APPENDER-ROLLINGFILEAPPENDER-INFO"/>
            <appender-ref ref="ASYNC-APPENDER-ROLLINGFILEAPPENDER-DEBUG"/>
            <appender-ref ref="ASYNC-APPENDER-ROLLINGFILEAPPENDER-ERROR"/>
            <!--异步滚动输出到logstash-->
            <appender-ref ref="ASYNC-APPENDER-LOGSTASH"/>
        </root>
    </springProfile>
</configuration>

PaymentMapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >

<mapper namespace="org.openatom.springcloud.dao.PaymentDao">

    <!--第一种写法:parameterType不写全路径-->
    <insert id="create" parameterType="Payment" useGeneratedKeys="true" keyProperty="id">
        insert into payment(serial)  values(#{serial});
    </insert>

    <resultMap id="BaseResultMap" type="Payment">
        <id column="id" property="id" jdbcType="BIGINT"/>
        <id column="serial" property="serial" jdbcType="VARCHAR"/>
    </resultMap>
    <select id="getPaymentById" parameterType="Long" resultMap="BaseResultMap">
        select * from payment where id=#{id};
    </select>

    <!--第二种写法:parameterType的写法与第一种有区别-->
    <!--
    <insert id="create" parameterType="org.openatom.springcloud.entities.Payment" useGeneratedKeys="true" keyProperty="id">
        insert into payment(serial)  values(#{serial});
    </insert>

    <resultMap id="BaseResultMap" type="org.openatom.springcloud.entities.Payment">
        <id column="id" property="id" jdbcType="BIGINT"/>
        <id column="serial" property="serial" jdbcType="VARCHAR"/>
    </resultMap>
    <select id="getPaymentById" parameterType="Long" resultMap="BaseResultMap">
        select * from payment where id=#{id};
    </select>
    -->
</mapper>



test环境配置文件
application.yml
#设置spring项目运行的环境
spring:
  profiles:
    active: '@profile.active@'


application-test.yml
server:
  port: 8010 #访问端口
spring:
  application:
    name: SPRINGCLOUD-BASIC-SAMPLE-PROVIDER-PAYMENT-SERVICE-CLUSTER-TEST #注意:服务名不要出现_
  devtools:
    restart:
      enabled: true
  # 将Client作为服务注册到SpringBootAdmin Server端,通过Server来监听项目的运行情况
  boot:
    admin:
      client:
        url: http://localhost:${server.port}
  logging:
    level: info
  datasource:
    type: com.alibaba.druid.pool.DruidDataSource            # 当前数据源操作类型
    driver-class-name: com.mysql.cj.jdbc.Driver              # mysql驱动包
    url: jdbc:mysql://192.168.0.5:3306/payment?useUnicode=true&characterEncoding=utf-8&useSSL=false
    username: root
    password: Mysql123456_

eureka:
  client:
    register-with-eureka: true  #表示是否将自己注册进EurekaServer默认为true。
    fetchRegistry: true  #是否从EurekaServer抓取已有的注册信息,默认为true。单节点无所谓,集群必须设置为true才能配合ribbon使用负载均衡
    service-url:
      #单机版
      defaultZone: http://localhost:7005/eureka
      #集群版
      #defaultZone: http://eureka7002:7002/eureka,http://eureka7003:7003/eureka,http://eureka7004:7004/eureka
  instance:
    instance-id: SPRINGCLOUD-PROVIDER-PAYMENT-SERVICE-CLUSTER-NODE-PAYMENT8010-TEST #Eureka仪表盘中Instances currently registered with Eureka.Status显示的内容
    #当前微服务所在部署机器ip
    ip-address: localhost
    prefer-ip-address: true  #访问路径可以显示IP地址,点击Eureka仪表盘中Instances currently registered with Eureka.Status显示的内容地址栏是否显示IP地址
    lease-renewal-interval-in-seconds: 30 #Eureka客户端向服务端发送心跳的时间间隔,单位为秒(默认是30秒)
    lease-expiration-duration-in-seconds: 90 #Eureka服务端在收到最后一次心跳后等待时间上限,单位为秒(默认是90秒),超时将剔除服务

mybatis:
  mapperLocations: classpath:mapper/*.xml
  type-aliases-package: org.openatom.springcloud.entities    # 所有Entity别名类所在包

#配置文件修改说明-------------------------------------------------:开始
#注意:不同的部署环境需要修改的配置
#   1.${logback.path}  #修改日志存放位置,Linxu为/,Windows为\
#       修改原因: Linux和Windows目录结构不同
#配置文件修改说明-------------------------------------------------:结束

#自定义日志配置文件路径
logging:
  config: classpath:logback-custom.xml
  path: /logs #所有日志存放在位置,加上\方便Linux环境下配置
  level:
    root: info #全局日志输出级别

logback:
  log-name: ${spring.application.name}
  append: false #是否启用append(追加到已经存在日志文件尾部),true:重启项目会追加新日志到之前日志,false:重启项目会清空之前的日志
  immediate-flush: true #是否启用immediateFlush(立即刷新),true:重启项目自动追加,false:重启项目会情况之前的日志
  deploy-machine-ip: ${eureka.instance.ip-address} #当前微服务所在部署机器ip

#logstash相关配置:开始
logstash:
  host: 192.168.0.4:5044 # logstash地址
  index: '@project.parent.artifactId@' # es中index名称
#logstash相关配置:结束

#actuator监控:开始
#通过下面的配置启用所有的监控端点,默认情况下,这些端点是禁用的;
management:
  endpoints:
    web:
      exposure:
        include: '*'
    enabled-by-default: true
  endpoint:
    health:
      show-details: always # 访问/actuator/health时,显示详细信息,而不是仅仅显示"status": "UP"
    # 日志文件路径:特别注意,此处无法配置日志文件路径,因为rancher会生成虚拟ip,这个虚拟ip是无法在这里获取的,
    #           但是虚拟ip是路径的一部分,所以这个路径无法拼接出来,所以这里无法配置日志文件路径
    #logfile:
    #  external-file:
#actuator监控:结束

logback-custom.xml
<?xml version="1.0" encoding="UTF-8"?>

<!--
    scan: 当此属性设置为true时,配置文件如果发生改变,将会被重新加载,默认值为true。
    scanPeriod: 设置监测配置文件是否有修改的时间间隔,如果没有给出时间单位,默认单位是毫秒。当scan为true时,此属性生效。默认的时间间隔为1分钟。
    debug: 当此属性设置为true时,将打印出logback内部日志信息,实时查看logback运行状态。默认值为false。
-->
<!-- 输出logback内部日志信息,每隔30s判断一下配置文件有没有更新,若更新,则重新加载 -->
<configuration scan="true" scanPeriod="30 seconds" debug="false">
    <!--从java代码中获取虚拟ip的值-->
    <!--获取当前微服务部署虚拟IP,如rancher为当前微服务分配的ip-->
    <define name="VIRTUAL_IP" class="org.openatom.springcloud.config.VirtualIpConfig"/>

    <!--从Spring容器中获取配置(Spring配置文件加载顺序:bootstrap.yml->logback.xml->application.yml)-->
    <!--获取当前微服务部署机器ip-->
    <springProperty name="MACHINE_IP" scope="context" source="logback.deploy-machine-ip"/>
    <!--应用名称-->
    <springProperty name="LOG_NAME" scope="context" source="logback.log-name"/>
    <!--是否启用append-->
    <springProperty name="IS_APPEND" scope="context" source="logback.append"/>
    <!--是否启用立即刷新-->
    <springProperty name="IS_IMMEDIATEFLUSH" scope="context" source="logback.immediate-flush"/>
    <springProperty name="LOG_PATH" scope="context" source="logging.path"/>
    <!--logstash地址-->
    <springProperty name="LOGSTASH_HOST" scope="context" source="logstash.host"/>
    <!--索引名称-->
    <springProperty name="INDEX_NAME" scope="context" source="logstash.index"/>


    <!-- name:变量的名称,可以随意起名,但建议名字要简明直译;value:变量的值;在配置文件中,我们可以用 ${} 的方式来使用,将变量引入到其他节点中去。-->
    <!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度 %msg:日志消息,%n是换行符-->
    <!--控制台日志输出预选样式-->
    <property name="CONSOLE_LOG_PATTERN_1" value="%red(%d{yyyy-MM-dd HH:mm:ss.SSS}) %green([%thread]) [machineIp:${MACHINE_IP} virtualIp:${VIRTUAL_IP}] [TraceId:%X{X-B3-TraceId:-} SpanId:%X{X-B3-SpanId:-} %highlight(%-5level) %boldMagenta(%logger{10}): %cyan(%msg%n)"/>
    <property name="CONSOLE_LOG_PATTERN_2" value="%yellow(%date{yyyy-MM-dd HH:mm:ss}) [machineIp:${MACHINE_IP} virtualIp:${VIRTUAL_IP}] [TraceId:%X{X-B3-TraceId:-} SpanId:%X{X-B3-SpanId:-} %highlight([%-5level]) %green(%logger) %msg%n"/>
    <property name="CONSOLE_LOG_PATTERN_3" value="%date{yyyy-MM-dd HH:mm:ss} [machineIp:${MACHINE_IP} virtualIp:${VIRTUAL_IP}] [TraceId:%X{X-B3-TraceId:-} SpanId:%X{X-B3-SpanId:-} Span-Export:%X{X-Span-Export:-}]  %green(%-5level) %boldMagenta(${PID:-}) -- [%+20thread] %cyan(%logger{20}) %line       : %msg%n"/>
    <!--文件中日志输出预选样式-->
    <property name="FILE_LOG_PATTERN_1" value="%d{yyyyMMdd:HH:mm:ss.SSS} [machineIp:${MACHINE_IP} virtualIp:${VIRTUAL_IP}] [TraceId:%X{X-B3-TraceId:-} SpanId:%X{X-B3-SpanId:-} [%thread] %-5level  %msg%n"/>

    <!--控制台日志输出格式-->
    <property name="CONSOLE_LOG_PATTERN" value="${CONSOLE_LOG_PATTERN_3}"/>
    <!--文件中日志输出格式-->
    <property name="FILE_LOG_PATTERN" value="${FILE_LOG_PATTERN_1}"/>
    <!--日志名称-->
    <!--定义默认日志输出级别-->
    <property name="LOG_OUTPUT_LEVEL" value="${LOG_LEVEL}" />
    <!--定义默认日志输出编码-->
    <property name="ENCODING" value="UTF-8" />

    <!-- 控制台输出:开始 -->
    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
        <!-- 用来设置日志的输入格式,使用“%+转换符”的方式,如果要输出”%”则必须使用”\”进行转义。-->
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <!-- 格式化输出:https://logback.qos.ch/manual/layouts.html
                 %d 表示日期,
                 %thread 表示线程名,
                 %level 日志级别从左显示5个字符宽度,
                 %t 线程名
                 %file:%line 文件名+行号,
                 %m 日志消息,%n是换行符
                 %X{traceId}:自定义设置的参数,后面会说。
            -->
            <pattern>${CONSOLE_LOG_PATTERN}</pattern>
            <charset>${ENCODING}</charset>
        </encoder>
    </appender>
    <!-- 控制台输出:结束 -->

    <!--输出到文件:开始-->
    <!-- 将项目本次运行INFO日志同步输出到文件,会自动清空文件中上一次的日志 -->
    <appender name="APPENDER-FILEAPPENDER-INFO" class="ch.qos.logback.core.FileAppender">
        <!-- 过滤器,只记录 info 级别以上的日志 -->
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <level>INFO</level>
        </filter>
        <!-- 写入的日志文件名,可以使相对目录也可以是绝对目录,如果上级目录不存在则自动创建 -->
        <file>${LOG_PATH}/${MACHINE_IP}/${VIRTUAL_IP}/${LOG_NAME}-info.log</file>
        <!-- 如果为true表示日志被追加到文件结尾,如果是false表示清空文件 -->
        <append>${IS_APPEND}</append>
        <!--立即刷新,设置成false可以提高日志吞吐量-->
        <immediateFlush>${IS_IMMEDIATEFLUSH}</immediateFlush>
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <pattern>${FILE_LOG_PATTERN}</pattern>
            <charset>${ENCODING}</charset>
        </encoder>
    </appender>

    <!-- 将项目本次运行INFO日志异步输出到文件,会自动清空文件中上一次的日志 -->
    <appender name="ASYNC-APPENDER-FILEAPPENDER-INFO" class="ch.qos.logback.classic.AsyncAppender">
        <appender-ref ref="APPENDER-FILEAPPENDER-INFO" />
        <!-- 设置异步阻塞队列的大小,为了不丢失日志建议设置的大一些,单机压测时100000是没问题的,应该不用担心OOM -->
        <queueSize>10000</queueSize>
        <!-- 设置丢弃DEBUG、TRACE、INFO日志的阀值,不丢失 -->
        <discardingThreshold>0</discardingThreshold>
        <!-- 设置队列入队时非阻塞,当队列满时会直接丢弃日志,但是对性能提升极大 -->
        <neverBlock>${IS_IMMEDIATEFLUSH}</neverBlock>
    </appender>

    <!-- 将项目本次运行DEBUG日志同步输出到文件,会自动清空文件中上一次的日志 -->
    <appender name="APPENDER-FILEAPPENDER-DEBUG" class="ch.qos.logback.core.FileAppender">
        <!-- 过滤器,只记录 info 级别以上的日志 -->
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <level>DEBUG</level>
        </filter>
        <!-- 写入的日志文件名,可以使相对目录也可以是绝对目录,如果上级目录不存在则自动创建 -->
        <file>${LOG_PATH}/${MACHINE_IP}/${VIRTUAL_IP}/${LOG_NAME}-debug.log</file>
        <!-- 如果为true表示日志被追加到文件结尾,如果是false表示清空文件 -->
        <append>${IS_APPEND}</append>
        <!--立即刷新,设置成false可以提高日志吞吐量-->
        <immediateFlush>true</immediateFlush>
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <pattern>${FILE_LOG_PATTERN}</pattern>
            <charset>${ENCODING}</charset>
        </encoder>
    </appender>

    <!-- 将项目本次运行DEBUG日志异步输出到文件,会自动清空文件中上一次的日志 -->
    <appender name="ASYNC-APPENDER-FILEAPPENDER-DEBUG" class="ch.qos.logback.classic.AsyncAppender">
        <appender-ref ref="APPENDER-FILEAPPENDER-DEBUG" />
        <!-- 设置异步阻塞队列的大小,为了不丢失日志建议设置的大一些,单机压测时100000是没问题的,应该不用担心OOM -->
        <queueSize>10000</queueSize>
        <!-- 设置丢弃DEBUG、TRACE、INFO日志的阀值,不丢失 -->
        <discardingThreshold>0</discardingThreshold>
        <!-- 设置队列入队时非阻塞,当队列满时会直接丢弃日志,但是对性能提升极大 -->
        <neverBlock>true</neverBlock>
    </appender>

    <!-- 将项目本次运行ERROR日志同步输出到文件,会自动清空文件中上一次的日志 -->
    <appender name="APPENDER-FILEAPPENDER-ERROR" class="ch.qos.logback.core.FileAppender">
        <!-- 过滤器,只记录 info 级别以上的日志 -->
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <level>DEBUG</level>
        </filter>
        <!-- 写入的日志文件名,可以使相对目录也可以是绝对目录,如果上级目录不存在则自动创建 -->
        <file>${LOG_PATH}/${MACHINE_IP}/${VIRTUAL_IP}/${LOG_NAME}-error.log</file>
        <!-- 如果为true表示日志被追加到文件结尾,如果是false表示清空文件 -->
        <append>${IS_APPEND}</append>
        <!--立即刷新,设置成false可以提高日志吞吐量-->
        <immediateFlush>${IS_IMMEDIATEFLUSH}</immediateFlush>
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <pattern>${FILE_LOG_PATTERN}</pattern>
            <charset>${ENCODING}</charset>
        </encoder>
    </appender>

    <!-- 将项目本次运行ERROR日志异步输出到文件,会自动清空文件中上一次的日志 -->
    <appender name="ASYNC-APPENDER-FILEAPPENDER-ERROR" class="ch.qos.logback.classic.AsyncAppender">
        <appender-ref ref="APPENDER-FILEAPPENDER-ERROR" />
        <!-- 设置异步阻塞队列的大小,为了不丢失日志建议设置的大一些,单机压测时100000是没问题的,应该不用担心OOM -->
        <queueSize>10000</queueSize>
        <!-- 设置丢弃DEBUG、TRACE、INFO日志的阀值,不丢失 -->
        <discardingThreshold>0</discardingThreshold>
        <!-- 设置队列入队时非阻塞,当队列满时会直接丢弃日志,但是对性能提升极大 -->
        <neverBlock>true</neverBlock>
    </appender>
    <!--输出到文件:结束-->


    <!--滚动输出到文件(按照天保存):开始-->
    <!-- 将项目本次运行INFO日志同步输出到文件,按照每天生成日志文件,会自动拼接上一次日志 -->
    <appender name="APPENDER-ROLLINGFILEAPPENDER-INFO" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <!-- 过滤器,只记录 info 级别以上的日志 -->
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <level>INFO</level>
        </filter>
        <!--立即刷新,设置成false可以提高日志吞吐量-->
        <immediateFlush>false</immediateFlush>
        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
            <!-- 日志文件输出的文件名:
                %d:可以包含一个Java.text.SimpleDateFormat指定的时间格式
                %i:自增数字
            -->
            <fileNamePattern>${LOG_PATH}/${MACHINE_IP}/${VIRTUAL_IP}/HISTORY/${LOG_NAME}-info-%d{yyyy-MM-dd}-index%i.log</fileNamePattern>
            <!-- 日志文件保存历史数量:控制保留的归档文件的最大数量,如果超出数量就删除旧文件 -->
            <maxHistory>10</maxHistory>
            <!-- 文件大小超过100MB归档 -->
            <maxFileSize>20MB</maxFileSize>
        </rollingPolicy>
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <pattern>${FILE_LOG_PATTERN}</pattern>
            <charset>${ENCODING}</charset>
        </encoder>
    </appender>

    <!-- 将项目本次运行INFO日志异步输出到文件,按照每天生成日志文件,会自动拼接上一次日志 -->
    <appender name="ASYNC-APPENDER-ROLLINGFILEAPPENDER-INFO" class="ch.qos.logback.classic.AsyncAppender">
        <appender-ref ref="APPENDER-ROLLINGFILEAPPENDER-INFO" />
        <!-- 设置异步阻塞队列的大小,为了不丢失日志建议设置的大一些,单机压测时100000是没问题的,应该不用担心OOM -->
        <queueSize>10000</queueSize>
        <!-- 设置丢弃DEBUG、TRACE、INFO日志的阀值,不丢失 -->
        <discardingThreshold>0</discardingThreshold>
        <!-- 设置队列入队时非阻塞,当队列满时会直接丢弃日志,但是对性能提升极大 -->
        <neverBlock>true</neverBlock>
    </appender>

    <!-- 将项目本次运行DEBUG日志同步输出到文件,按照每天生成日志文件,会自动拼接上一次日志 -->
    <appender name="APPENDER-ROLLINGFILEAPPENDER-DEBUG" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <!-- 过滤器,只记录 info 级别以上的日志 -->
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <level>DEBUG</level>
        </filter>
        <!--立即刷新,设置成false可以提高日志吞吐量-->
        <immediateFlush>false</immediateFlush>
        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
            <!-- 日志文件输出的文件名:
                %d:可以包含一个Java.text.SimpleDateFormat指定的时间格式
                %i:自增数字
            -->
            <fileNamePattern>${LOG_PATH}/${MACHINE_IP}/${VIRTUAL_IP}/HISTORY/${LOG_NAME}-debug-%d{yyyy-MM-dd}-index%i.log</fileNamePattern>
            <!-- 日志文件保存历史数量:控制保留的归档文件的最大数量,如果超出数量就删除旧文件 -->
            <maxHistory>10</maxHistory>
            <!-- 文件大小超过100MB归档 -->
            <maxFileSize>20MB</maxFileSize>
        </rollingPolicy>
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <pattern>${FILE_LOG_PATTERN}</pattern>
            <charset>${ENCODING}</charset>
        </encoder>
    </appender>

    <!-- 将项目本次运行DEBUG日志异步输出到文件,按照每天生成日志文件,会自动拼接上一次日志 -->
    <appender name="ASYNC-APPENDER-ROLLINGFILEAPPENDER-DEBUG" class="ch.qos.logback.classic.AsyncAppender">
        <appender-ref ref="APPENDER-ROLLINGFILEAPPENDER-DEBUG" />
        <!-- 设置异步阻塞队列的大小,为了不丢失日志建议设置的大一些,单机压测时100000是没问题的,应该不用担心OOM -->
        <queueSize>10000</queueSize>
        <!-- 设置丢弃DEBUG、TRACE、INFO日志的阀值,不丢失 -->
        <discardingThreshold>0</discardingThreshold>
        <!-- 设置队列入队时非阻塞,当队列满时会直接丢弃日志,但是对性能提升极大 -->
        <neverBlock>true</neverBlock>
    </appender>

    <!-- 将项目本次运行ERROR日志同步输出到文件,按照每天生成日志文件,会自动拼接上一次日志 -->
    <appender name="APPENDER-ROLLINGFILEAPPENDER-ERROR" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <!-- 过滤器,只记录error级别的日志 -->
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>ERROR</level>
            <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>
        <!--立即刷新,设置成false可以提高日志吞吐量-->
        <immediateFlush>false</immediateFlush>
        <!-- 每天生成一个日志文件,保存30天的日志文件 -->
        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
            <!-- 日志文件输出的文件名:按天回滚 daily -->
            <fileNamePattern>${LOG_PATH}/${MACHINE_IP}/${VIRTUAL_IP}/HISTORY/${LOG_NAME}-error-%d{yyyy-MM-dd}-index%i.log</fileNamePattern>
            <!-- 日志文件保留天数 -->
            <maxHistory>10</maxHistory>
            <!-- 文件大小超过100MB归档 -->
            <maxFileSize>20MB</maxFileSize>
        </rollingPolicy>
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <pattern>${FILE_LOG_PATTERN}</pattern>
            <charset>utf8</charset>
        </encoder>
    </appender>

    <appender name="ASYNC-APPENDER-ROLLINGFILEAPPENDER-ERROR" class="ch.qos.logback.classic.AsyncAppender">
        <appender-ref ref="APPENDER-ROLLINGFILEAPPENDER-ERROR" />
        <!-- 设置异步阻塞队列的大小,为了不丢失日志建议设置的大一些,单机压测时100000是没问题的,应该不用担心OOM -->
        <queueSize>10000</queueSize>
        <!-- 设置丢弃DEBUG、TRACE、INFO日志的阀值,不丢失 -->
        <discardingThreshold>0</discardingThreshold>
        <!-- 设置队列入队时非阻塞,当队列满时会直接丢弃日志,但是对性能提升极大 -->
        <neverBlock>true</neverBlock>
    </appender>
    <!--滚动输出到文件(按照天保存):结束-->

    <!--输出到LOGSTASH:开始-->
    <!-- 将项目本次运行ERROR日志同步输出到文件,按照每天生成日志文件,会自动拼接上一次日志 -->
    <appender name="APPENDER-LOGSTASH" class="net.logstash.logback.appender.LogstashTcpSocketAppender">
        <!--  logstash服务器地址-->
        <destination>${LOGSTASH_HOST}</destination>
        <encoder class="net.logstash.logback.encoder.LoggingEventCompositeJsonEncoder">
            <providers>
                <pattern>
                    <pattern>
                        {
                        "appName":"${INDEX_NAME}",
                        "machineIp":"${MACHINE_IP}",
                        "virtualIp":"${VIRTUAL_IP}",
                        "serviceName":"${LOG_NAME}",
                        "timestamp": "%date{\"yyyy-MM-dd'T'HH:mm:ss,SSSZ\"}",
                        "logLevel":"%level",
                        "message":"%msg%n",
                        "traceId": "%X{X-B3-TraceId:-}",
                        "spanId": "%X{X-B3-SpanId:-}",
                        "spanExport": "%X{X-Span-Export:-}"
                        }
                    </pattern>
                </pattern>
            </providers>
        </encoder>
    </appender>
    <appender name="ASYNC-APPENDER-LOGSTASH" class="ch.qos.logback.classic.AsyncAppender">
        <appender-ref ref="APPENDER-LOGSTASH" />
        <!-- 设置异步阻塞队列的大小,为了不丢失日志建议设置的大一些,单机压测时100000是没问题的,应该不用担心OOM -->
        <queueSize>10000</queueSize>
        <!-- 设置丢弃DEBUG、TRACE、INFO日志的阀值,不丢失 -->
        <discardingThreshold>0</discardingThreshold>
        <!-- 设置队列入队时非阻塞,当队列满时会直接丢弃日志,但是对性能提升极大 -->
        <neverBlock>true</neverBlock>
    </appender>
    <!--输出到logstash:结束-->

    <!--
        开发环境日志级别为DEBUG
        level:用来设置打印级别
        五个常用打印级别从低至高依次为TRACE、DEBUG、INFO、WARN、ERROR
    -->
    <springProfile name="dev">
        <root>
            <!--输出到控制台-->
            <appender-ref ref="STDOUT"/>
            <!--异步非滚动输出到文件-->
            <appender-ref ref="ASYNC-APPENDER-FILEAPPENDER-INFO"/>
            <appender-ref ref="ASYNC-APPENDER-FILEAPPENDER-DEBUG"/>
            <appender-ref ref="ASYNC-APPENDER-FILEAPPENDER-ERROR"/>
            <!--异步滚动输出到文件:dev环境不开启-->
<!--            <appender-ref ref="ASYNC-APPENDER-ROLLINGFILEAPPENDER-INFO"/>-->
<!--            <appender-ref ref="ASYNC-APPENDER-ROLLINGFILEAPPENDER-DEBUG"/>-->
<!--            <appender-ref ref="ASYNC-APPENDER-ROLLINGFILEAPPENDER-ERROR"/>-->
            <!--异步滚动输出到logstash-->
            <appender-ref ref="ASYNC-APPENDER-LOGSTASH"/>
        </root>
    </springProfile>

    <!-- 测试环境日志级别为INFO -->
    <springProfile name="test">
        <root>
            <!--输出到控制台-->
            <appender-ref ref="STDOUT"/>
            <!--异步非滚动输出到文件-->
            <appender-ref ref="ASYNC-APPENDER-FILEAPPENDER-INFO"/>
            <appender-ref ref="ASYNC-APPENDER-FILEAPPENDER-DEBUG"/>
            <appender-ref ref="ASYNC-APPENDER-FILEAPPENDER-ERROR"/>
            <!--异步滚动输出到文件:test环境不开启-->
<!--            <appender-ref ref="ASYNC-APPENDER-ROLLINGFILEAPPENDER-INFO"/>-->
<!--            <appender-ref ref="ASYNC-APPENDER-ROLLINGFILEAPPENDER-DEBUG"/>-->
<!--            <appender-ref ref="ASYNC-APPENDER-ROLLINGFILEAPPENDER-ERROR"/>-->
            <!--异步滚动输出到logstash-->
            <appender-ref ref="ASYNC-APPENDER-LOGSTASH"/>
        </root>
    </springProfile>

    <!-- 生产环境日志级别为INFO -->
    <springProfile name="prod">
        <root>
            <!--输出到控制台-->
            <appender-ref ref="STDOUT"/>
            <!--异步非滚动输出到文件-->
            <appender-ref ref="ASYNC-APPENDER-FILEAPPENDER-INFO"/>
            <appender-ref ref="ASYNC-APPENDER-FILEAPPENDER-DEBUG"/>
            <appender-ref ref="ASYNC-APPENDER-FILEAPPENDER-ERROR"/>
            <!--异步滚动输出到文件-->
            <appender-ref ref="ASYNC-APPENDER-ROLLINGFILEAPPENDER-INFO"/>
            <appender-ref ref="ASYNC-APPENDER-ROLLINGFILEAPPENDER-DEBUG"/>
            <appender-ref ref="ASYNC-APPENDER-ROLLINGFILEAPPENDER-ERROR"/>
            <!--异步滚动输出到logstash-->
            <appender-ref ref="ASYNC-APPENDER-LOGSTASH"/>
        </root>
    </springProfile>

    <!-- rancher环境日志级别为INFO -->
    <springProfile name="rancher">
        <root>
            <!--输出到控制台-->
            <appender-ref ref="STDOUT"/>
            <!--异步非滚动输出到文件-->
            <appender-ref ref="ASYNC-APPENDER-FILEAPPENDER-INFO"/>
            <appender-ref ref="ASYNC-APPENDER-FILEAPPENDER-DEBUG"/>
            <appender-ref ref="ASYNC-APPENDER-FILEAPPENDER-ERROR"/>
            <!--异步滚动输出到文件-->
            <appender-ref ref="ASYNC-APPENDER-ROLLINGFILEAPPENDER-INFO"/>
            <appender-ref ref="ASYNC-APPENDER-ROLLINGFILEAPPENDER-DEBUG"/>
            <appender-ref ref="ASYNC-APPENDER-ROLLINGFILEAPPENDER-ERROR"/>
            <!--异步滚动输出到logstash-->
            <appender-ref ref="ASYNC-APPENDER-LOGSTASH"/>
        </root>
    </springProfile>
</configuration>

PaymentMapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >

<mapper namespace="org.openatom.springcloud.dao.PaymentDao">

    <!--第一种写法:parameterType不写全路径-->
    <insert id="create" parameterType="Payment" useGeneratedKeys="true" keyProperty="id">
        insert into payment(serial)  values(#{serial});
    </insert>

    <resultMap id="BaseResultMap" type="Payment">
        <id column="id" property="id" jdbcType="BIGINT"/>
        <id column="serial" property="serial" jdbcType="VARCHAR"/>
    </resultMap>
    <select id="getPaymentById" parameterType="Long" resultMap="BaseResultMap">
        select * from payment where id=#{id};
    </select>

    <!--第二种写法:parameterType的写法与第一种有区别-->
    <!--
    <insert id="create" parameterType="org.openatom.springcloud.entities.Payment" useGeneratedKeys="true" keyProperty="id">
        insert into payment(serial)  values(#{serial});
    </insert>

    <resultMap id="BaseResultMap" type="org.openatom.springcloud.entities.Payment">
        <id column="id" property="id" jdbcType="BIGINT"/>
        <id column="serial" property="serial" jdbcType="VARCHAR"/>
    </resultMap>
    <select id="getPaymentById" parameterType="Long" resultMap="BaseResultMap">
        select * from payment where id=#{id};
    </select>
    -->
</mapper>



20.7.6.编写模块dao

package org.openatom.springcloud.dao;

import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.openatom.springcloud.entities.Payment;

@Mapper
public interface PaymentDao {

    int create(Payment payment);

    Payment getPaymentById(@Param("id") Long id);
}

20.7.7.编写模块service

package org.openatom.springcloud.service;

import org.apache.ibatis.annotations.Param;
import org.openatom.springcloud.entities.Payment;

public interface PaymentService {

    int create(Payment payment);

    Payment getPaymentById(@Param("id") Long id);
}

20.7.8.编写模块service实现类

package org.openatom.springcloud.service.impl;

import org.openatom.springcloud.dao.PaymentDao;
import org.openatom.springcloud.service.PaymentService;
import org.springframework.stereotype.Service;
import org.openatom.springcloud.entities.Payment;

import javax.annotation.Resource;


@Service
public class PaymentServiceImpl implements PaymentService {

    @Resource
    private PaymentDao paymentDao;

    public int create(Payment payment) {
        return paymentDao.create(payment);
    }

    public Payment getPaymentById(Long id) {
        return paymentDao.getPaymentById(id);
    }
}

20.7.9.编写模块config

package org.openatom.springcloud.config;

import ch.qos.logback.core.PropertyDefinerBase;
import lombok.extern.slf4j.Slf4j;

import java.net.InetAddress;
import java.net.UnknownHostException;

@Slf4j
public class VirtualIpConfig extends PropertyDefinerBase {
    private static String virtualIp;
    static {
        try {
            virtualIp = InetAddress.getLocalHost().getHostAddress();
        } catch (UnknownHostException e) {
            log.error("获取日志Ip异常", e);
            virtualIp = null;
        }
    }

    @Override
    public String getPropertyValue() {
        return virtualIp;
    }
}

20.7.10.编写模块controller

package org.openatom.springcloud.controller;

import lombok.extern.slf4j.Slf4j;
import org.openatom.springcloud.service.PaymentService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.*;
import org.openatom.springcloud.entities.CommonResult;
import org.openatom.springcloud.entities.Payment;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.concurrent.TimeUnit;

@RestController
@Slf4j
public class PaymentController {

    @Resource
    private PaymentService paymentService;

    @Value("${server.port}")
    private String serverPort;

    @Autowired
    private HttpServletRequest request;

    //从配置文件中动态获取服务名称
    @Value("${spring.application.name}")
    private String APPLICATION_NAME;

    @PostMapping(value = "/provider/payment/create")
    public CommonResult create(@RequestBody Payment payment) {
        int result = paymentService.create(payment);
        log.info("*****插入结果:"+result);
        if(result > 0) {
            return new CommonResult(200,"插入数据库成功,serverPort: "+serverPort,result);
        }else{
            return new CommonResult(444,"插入数据库失败",null);
        }
    }

    /**
     * rancher扩容缩容测试专用方法
     * @param id
     * @return
     */
    @GetMapping(value = "/provider/payment/get/{id}")
    public CommonResult<Payment> getPaymentById(@PathVariable("id") Long id) {
        log.info("-------------------------------------------");
        log.info("应用名称1:" + APPLICATION_NAME +
                ",配置文件中的端口号:" + serverPort +
                ",localAddr" + request.getLocalAddr() +
                ",LocalPort:" + request.getLocalPort() +
                ",RemotePort:" + request.getRemotePort() +
                ",ServerPort:" + request.getServerPort());
        log.info("-------------------------------------------");
        Payment payment = paymentService.getPaymentById(id);
        if(payment != null){
            return new CommonResult(200,"查询成功,localAddr: " + request.getLocalAddr(), payment);
        }else{
            return new CommonResult(444,"没有对应记录,查询ID: "+id,null);
        }
    }

    /**
     * 用来测试OpenFeign远程调用超时报异常的方法
     * @return
     */
    @GetMapping(value = "/provider/payment/openfeign/timeout")
    public String getPaymentByIdOpenFeignTimeout() {
        // 业务逻辑处理正确,但是需要耗费3秒钟
        try {
            TimeUnit.SECONDS.sleep(3);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return serverPort;
    }
}

20.7.11.编写模块主启动类

package org.openatom.springcloud;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;

/**
 * 支付接口提供端
 *  使用Eureka作为注册中心
 */
@EnableEurekaClient
@SpringBootApplication
public class BasicSamplePaymentServiceProviderClusterNode8010 {

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

}

20.8.搭建服务消费者

20.8.1.模块简介

为综合案例搭建服务消费者,启动端口: 80

20.8.2.模块目录结构

springcloud-basic-sample-consumer-loadbalance-openfeign-configuration-order80
|-- docker
|   •-- Dockerfile
|-- src
|   •-- main
|       |-- java
|       |   •-- org
|       |       •-- openatom
|       |           •-- springcloud
|       |               |-- config
|       |               |   |-- DynamicFeignClientFactoryConfig.java
|       |               |   |-- OpenFeignConfig.java
|       |               |   •-- VirtualIpConfig.java
|       |               |-- controller
|       |               |   |-- OrderConsumerController.java
|       |               |   •-- OrderConsumerControllerDynamicFeignClientFactory.java
|       |               |-- interceptor
|       |               |   •-- FeignClientRequestInterceptor.java
|       |               |-- service
|       |               |   |-- PaymentServiceOpenFeign.java
|       |               |   •-- PaymentServiceOpenFeignDynamicFeignClientFactory.java
|       |               •-- BasicSampleOrderServiceConsumerLoadBalanceOpenFeignConfiguration80.java
|       •-- resources
|           |-- dev
|           |   |-- application-dev.yml
|           |   |-- application.yml
|           |   •-- logback-custom.xml
|           |-- prod
|           |   |-- application-prod.yml
|           |   |-- application.yml
|           |   •-- logback-custom.xml
|           |-- rancher
|           |   |-- application-rancher.yml
|           |   |-- application.yml
|           |   •-- logback-custom.xml
|           •-- test
|               |-- application-test.yml
|               |-- application.yml
|               •-- logback-custom.xml
•-- pom.xml

20.8.3.创建模块

在父工程(springcloud-eureka)中创建一个名为springcloud-basic-sample-consumer-loadbalance-openfeign-configuration-order80的maven模块,注意:当前模块创建成功后,在父工程pom.xml中<modules></modules>中会自动生成有关当前模块的信息

20.8.4.编写模块pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>springcloud-eureka</artifactId>
        <groupId>org.openatom</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>springcloud-basic-sample-consumer-loadbalance-openfeign-configuration-order80</artifactId>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
        <!--设置当前服务端口-->
        <docker.container.port>80</docker.container.port>
        <!--docker容器端口映射-->
        <docker.port.mapping>${docker.container.port}:${docker.container.port}</docker.port.mapping>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
        <!--引入公共的工程-->
        <dependency>
            <groupId>org.openatom</groupId>
            <artifactId>springcloud-api-commons</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>
        <dependency>
            <groupId>net.logstash.logback</groupId>
            <artifactId>logstash-logback-encoder</artifactId>
        </dependency>
        <dependency>
            <groupId>de.codecentric</groupId>
            <artifactId>spring-boot-admin-starter-client</artifactId>
        </dependency>
        <!--包含了sleuth+zipkin-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-zipkin</artifactId>
        </dependency>
    </dependencies>

    <!--热部署需要加这个-->
    <build>
        <finalName>${project.artifactId}</finalName>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <executions>
                    <execution>
                        <!--把当前插件repackage命令和maven的package绑定-->
                        <id>repackage-original</id>
                        <phase>package</phase>
                        <goals>
                            <goal>repackage</goal>
                        </goals>
                    </execution>
                </executions>
                <configuration>
                    <fork>true</fork>
                    <addResources>true</addResources>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-resources-plugin</artifactId>
                <configuration>
                    <encoding>UTF-8</encoding>
                    <delimiters>
                        <delimiter>@</delimiter>
                    </delimiters>
                    <useDefaultDelimiters>false</useDefaultDelimiters>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-antrun-plugin</artifactId>
                <executions>
                    <execution>
                        <id>del-jar</id>
                        <phase>clean</phase>
                        <configuration>
                            <tasks>
                                <!-- 这是将当前模块下的target下的jar包删除-->
                                <delete file="docker/${build.finalName}.jar"/>
                            </tasks>
                        </configuration>
                        <goals>
                            <goal>run</goal>
                        </goals>
                    </execution>
                    <execution>
                        <id>copy-jar</id>
                        <phase>install</phase>
                        <configuration>
                            <tasks>
                                <!-- 这是将当前模块下的target下的jar包copy到当前模块根目录下docker目录中-->
                                <copy todir="docker" file="target/${build.finalName}.jar"></copy>
                            </tasks>
                        </configuration>
                        <goals>
                            <goal>run</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
            <plugin>
                <groupId>io.fabric8</groupId>
                <artifactId>docker-maven-plugin</artifactId>
                <configuration>
                    <dockerHost>${docker.host}</dockerHost>
                    <removeMode>true</removeMode>
                    <!--
                        harbor镜像仓库认证配置
                        注意:不管是harbor中是公开项目还是私密项目,这个配置都要加,不加无法push成功
                    -->
                    <authConfig>
                        <username>${docker.registry.username}</username>
                        <password>${docker.registry.password}</password>
                    </authConfig>
                    <images>
                        <image>
                            <!--显示日志的时候-->
                            <!--<alias>spring-cloud-eureka</alias>-->
                            <!--如果只给docker本地镜像库中推送,格式为 命名空间/项目名称:tags名称,示例:项目artifactId/模块artifactId-->
                            <!--<name>${project.parent.artifactId}/${project.name}</name>-->
                            <!--
                                如果要同时给私服中推送,格式为 registry的ip:命名空间/项目名称:tags名称,示例:私服的ip:项目artifactId/模块artifactId
                                也可将registry单独写在下面
                            -->
                            <!--<name>镜像名称:${docker.registry}/${project.parent.artifactId}/${project.name}</name>-->
                            <name>${project.parent.artifactId}/${project.name}:latest</name>
                            <registry>${docker.registry.uri}</registry>
                            <!--定义镜像构建行为-->
                            <build>
                                <!-- 指定dockerfile文件的位置-->
                                <dockerFile>${project.basedir}/docker/Dockerfile</dockerFile>
                            </build>
                            <!-- 定义容器启动行为-->
                            <run>
                                <!--设置容器名,可采用通配符-->
                                <containerNamePattern>${project.parent.artifactId}_${project.build.finalName}</containerNamePattern>
                                <!--设置端口映射-->
                                <ports>
                                    <port>${docker.port.mapping}</port>
                                </ports>
                                <links>
                                    <link>mysql</link>
                                </links>
                            </run>
                        </image>
                    </images>
                    <buildArgs>
                        <!--docker私服地址-->
                        <DOCKER_REGISTRY_URL>${docker.registry.uri}</DOCKER_REGISTRY_URL>
                    </buildArgs>
                </configuration>
                <executions>
                    <!--如果想在项目install时构建镜像添加-->
                    <execution>
                        <id>build-image</id>
                        <phase>install</phase>
                        <goals>
                            <goal>build</goal>
                        </goals>
                    </execution>
                    <!--如果想在项目install时构建镜像添加-->
                    <execution>
                        <id>tag-image</id>
                        <phase>install</phase>
                        <goals>
                            <goal>tag</goal>
                        </goals>
                    </execution>
                    <!--如果想在项目install时推送镜像到私服添加-->
                    <execution>
                        <id>push-image</id>
                        <phase>install</phase>
                        <goals>
                            <goal>push</goal>
                        </goals>
                    </execution>
                    <!--如果想在项目install时推送镜像到私服后删除并docker中本地build的镜像添加-->
                    <execution>
                        <id>remove-image</id>
                        <phase>install</phase>
                        <goals>
                            <goal>remove</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
        <!--打包多环境-->
        <resources>
            <resource>
                <directory>src/main/resources</directory>
                <excludes>
                    <exclude>**/*.yml</exclude>
                    <exclude>**/*.xml</exclude>
                </excludes>
            </resource>
            <resource>
                <directory>src/main/resources/${profile.active}</directory>
                <!--引入所需环境的配置文件-->
                <filtering>true</filtering>
                <includes>
                    <include>application.yml</include>
                    <!--根据maven选择环境导入配置文件-->
                    <include>application-${profile.active}.yml</include>
                    <include>mapper/*.xml</include>
                    <include>*.xml</include>
                </includes>
            </resource>
        </resources>
    </build>
</project>

20.8.5.编写模块配置文件

dev环境配置文件
application.yml
#设置spring项目运行的环境
spring:
  profiles:
    active: '@profile.active@'


application-dev.yml
server:
  port: 80
spring:
  application:
    name: SPRINGCLOUD-BASIC-SAMPLE-CONSUMER-LOADBALANCE-OPENFEIGN-DYNAMIC-SERVICENAME-ORDER80-DEV #注意:服务名不要出现_
  devtools:
    restart:
      enabled: true
  logging: #Spring运行日志配置
    level: info
  zipkin:
    base-url: http://localhost:9411
  sleuth:
    sampler:
      probability: 1  # span的采样率,默认为 0.1,这个值介于0到1之间

eureka:
  client:
    register-with-eureka: true  #表示是否将自己注册进EurekaServer默认为true。
    fetchRegistry: true  #是否从EurekaServer抓取已有的注册信息,默认为true。服务提供端是单节点无所谓,是集群必须设置为true才能配合ribbon使用负载均衡,否则报异常No instances available for SPRINGCLOUD-PROVIDER-PAYMENT-SERVICE-CLUSTER
    service-url:
      #单机版
      defaultZone: http://localhost:7005/eureka
      #集群版
      #defaultZone: http://eureka7002:7002/eureka,http://eureka7003:7003/eureka,http://eureka7004:7004/eureka
  instance:
    instance-id: ${spring.application.name} #Eureka仪表盘中Instances currently registered with Eureka.Status显示的内容
    #当前微服务所在部署机器ip
    ip-address: localhost
    prefer-ip-address: false #访问路径可以显示IP地址,点击Eureka仪表盘中Instances currently registered with Eureka.Status显示的内容地址栏是否显示IP地址

#服务提供端信息
service:
  provider:
    provider-1: &provider-1 SPRINGCLOUD-BASIC-SAMPLE-PROVIDER-PAYMENT-SERVICE-CLUSTER-${spring.profiles.active}  #服务提供端名称

#某个/某些服务的Ribbon配置
*provider-1: #服务提供端名称
  ribbon:
    NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule  #Ribbon负载均衡规则类所在的路径,自带七种规则,也可以是自定位规则的类所在的路径
#对OpenFeign进行单独配置
feign:
  client:
    config:
      #这里填具体的服务名称(也可以填default,表示对所有服务生效)
      *provider-1:  #服务提供端名称
        #connectTimeout和readTimeout这两个得一起配置才会生效
        connectTimeout: 5000  #指的是建立连接所用的时间,适用于网络状况正常的情况下,两端连接所用的时间
        readTimeout: 5000   #指的是建立连接后从服务器读取到可用资源所用的时间

#配置文件修改说明-------------------------------------------------:开始
#注意:不同的部署环境需要修改的配置
#   1.${logback.path}  #修改日志存放位置,Linxu为/,Windows为\
#       修改原因: Linux和Windows目录结构不同
#配置文件修改说明-------------------------------------------------:结束

#自定义日志配置文件路径
logging:
  config: classpath:logback-custom.xml
  path: D:\repository\workspace\IDEA\PERSONAL\springcloud-eureka\log\ #所有日志存放在位置,加上\方便Linux环境下配置
  level:
    root: info #全局日志输出级别
    org.openatom.springcloud.services.PaymentServiceOpenFeign: debug  #OpenFeign增强日志配置,OpenFeign日志以什么级别监控哪个接口
    org.openatom.springcloud.services.PaymentServiceOpenFeignDynamicFeignClientFactory: debug  #OpenFeign增强日志配置,OpenFeign日志以什么级别监控哪个接口

logback:
  log-name: ${spring.application.name}
  append: false #是否启用append(追加到已经存在日志文件尾部),true:重启项目会追加新日志到之前日志,false:重启项目会清空之前的日志
  immediate-flush: true #是否启用immediateFlush(立即刷新),true:重启项目自动追加,false:重启项目会情况之前的日志
  deploy-machine-ip: ${eureka.instance.ip-address} #当前微服务所在部署机器ip

#logstash相关配置:开始
logstash:
  host: 192.168.0.4:5044 # logstash地址
  index: '@project.parent.artifactId@' # es中index名称
#logstash相关配置:结束

#actuator监控:开始
#通过下面的配置启用所有的监控端点,默认情况下,这些端点是禁用的;
management:
  endpoints:
    web:
      exposure:
        include: '*'
    enabled-by-default: true
  endpoint:
    health:
      show-details: always # 访问/actuator/health时,显示详细信息,而不是仅仅显示"status": "UP"
    # 日志文件路径:特别注意,此处无法配置日志文件路径,因为rancher会生成虚拟ip,这个虚拟ip是无法在这里获取的,
    #           但是虚拟ip是路径的一部分,所以这个路径无法拼接出来,所以这里无法配置日志文件路径
    #logfile:
    #  external-file:
#actuator监控:结束

logback-custom.xml
<?xml version="1.0" encoding="UTF-8"?>

<!--
    scan: 当此属性设置为true时,配置文件如果发生改变,将会被重新加载,默认值为true。
    scanPeriod: 设置监测配置文件是否有修改的时间间隔,如果没有给出时间单位,默认单位是毫秒。当scan为true时,此属性生效。默认的时间间隔为1分钟。
    debug: 当此属性设置为true时,将打印出logback内部日志信息,实时查看logback运行状态。默认值为false。
-->
<!-- 输出logback内部日志信息,每隔30s判断一下配置文件有没有更新,若更新,则重新加载 -->
<configuration scan="true" scanPeriod="30 seconds" debug="false">
    <!--从java代码中获取虚拟ip的值-->
    <!--获取当前微服务部署虚拟IP,如rancher为当前微服务分配的ip-->
    <define name="VIRTUAL_IP" class="org.openatom.springcloud.config.VirtualIpConfig"/>

    <!--从Spring容器中获取配置(Spring配置文件加载顺序:bootstrap.yml->logback.xml->application.yml)-->
    <!--获取当前微服务部署机器ip-->
    <springProperty name="MACHINE_IP" scope="context" source="logback.deploy-machine-ip"/>
    <!--应用名称-->
    <springProperty name="LOG_NAME" scope="context" source="logback.log-name"/>
    <!--是否启用append-->
    <springProperty name="IS_APPEND" scope="context" source="logback.append"/>
    <!--是否启用立即刷新-->
    <springProperty name="IS_IMMEDIATEFLUSH" scope="context" source="logback.immediate-flush"/>
    <springProperty name="LOG_PATH" scope="context" source="logging.path"/>
    <!--logstash地址-->
    <springProperty name="LOGSTASH_HOST" scope="context" source="logstash.host"/>
    <!--索引名称-->
    <springProperty name="INDEX_NAME" scope="context" source="logstash.index"/>


    <!-- name:变量的名称,可以随意起名,但建议名字要简明直译;value:变量的值;在配置文件中,我们可以用 ${} 的方式来使用,将变量引入到其他节点中去。-->
    <!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度 %msg:日志消息,%n是换行符-->
    <!--控制台日志输出预选样式-->
    <property name="CONSOLE_LOG_PATTERN_1" value="%red(%d{yyyy-MM-dd HH:mm:ss.SSS}) %green([%thread]) [machineIp:${MACHINE_IP} virtualIp:${VIRTUAL_IP}] [TraceId:%X{X-B3-TraceId:-} SpanId:%X{X-B3-SpanId:-} %highlight(%-5level) %boldMagenta(%logger{10}): %cyan(%msg%n)"/>
    <property name="CONSOLE_LOG_PATTERN_2" value="%yellow(%date{yyyy-MM-dd HH:mm:ss}) [machineIp:${MACHINE_IP} virtualIp:${VIRTUAL_IP}] [TraceId:%X{X-B3-TraceId:-} SpanId:%X{X-B3-SpanId:-} %highlight([%-5level]) %green(%logger) %msg%n"/>
    <property name="CONSOLE_LOG_PATTERN_3" value="%date{yyyy-MM-dd HH:mm:ss} [machineIp:${MACHINE_IP} virtualIp:${VIRTUAL_IP}] [TraceId:%X{X-B3-TraceId:-} SpanId:%X{X-B3-SpanId:-} Span-Export:%X{X-Span-Export:-}]  %green(%-5level) %boldMagenta(${PID:-}) -- [%+20thread] %cyan(%logger{20}) %line       : %msg%n"/>
    <!--文件中日志输出预选样式-->
    <property name="FILE_LOG_PATTERN_1" value="%d{yyyyMMdd:HH:mm:ss.SSS} [machineIp:${MACHINE_IP} virtualIp:${VIRTUAL_IP}] [TraceId:%X{X-B3-TraceId:-} SpanId:%X{X-B3-SpanId:-} [%thread] %-5level  %msg%n"/>

    <!--控制台日志输出格式-->
    <property name="CONSOLE_LOG_PATTERN" value="${CONSOLE_LOG_PATTERN_3}"/>
    <!--文件中日志输出格式-->
    <property name="FILE_LOG_PATTERN" value="${FILE_LOG_PATTERN_1}"/>
    <!--日志名称-->
    <!--定义默认日志输出级别-->
    <property name="LOG_OUTPUT_LEVEL" value="${LOG_LEVEL}" />
    <!--定义默认日志输出编码-->
    <property name="ENCODING" value="UTF-8" />

    <!-- 控制台输出:开始 -->
    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
        <!-- 用来设置日志的输入格式,使用“%+转换符”的方式,如果要输出”%”则必须使用”\”进行转义。-->
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <!-- 格式化输出:https://logback.qos.ch/manual/layouts.html
                 %d 表示日期,
                 %thread 表示线程名,
                 %level 日志级别从左显示5个字符宽度,
                 %t 线程名
                 %file:%line 文件名+行号,
                 %m 日志消息,%n是换行符
                 %X{traceId}:自定义设置的参数,后面会说。
            -->
            <pattern>${CONSOLE_LOG_PATTERN}</pattern>
            <charset>${ENCODING}</charset>
        </encoder>
    </appender>
    <!-- 控制台输出:结束 -->

    <!--输出到文件:开始-->
    <!-- 将项目本次运行INFO日志同步输出到文件,会自动清空文件中上一次的日志 -->
    <appender name="APPENDER-FILEAPPENDER-INFO" class="ch.qos.logback.core.FileAppender">
        <!-- 过滤器,只记录 info 级别以上的日志 -->
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <level>INFO</level>
        </filter>
        <!-- 写入的日志文件名,可以使相对目录也可以是绝对目录,如果上级目录不存在则自动创建 -->
        <file>${LOG_PATH}/${MACHINE_IP}/${VIRTUAL_IP}/${LOG_NAME}-info.log</file>
        <!-- 如果为true表示日志被追加到文件结尾,如果是false表示清空文件 -->
        <append>${IS_APPEND}</append>
        <!--立即刷新,设置成false可以提高日志吞吐量-->
        <immediateFlush>${IS_IMMEDIATEFLUSH}</immediateFlush>
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <pattern>${FILE_LOG_PATTERN}</pattern>
            <charset>${ENCODING}</charset>
        </encoder>
    </appender>

    <!-- 将项目本次运行INFO日志异步输出到文件,会自动清空文件中上一次的日志 -->
    <appender name="ASYNC-APPENDER-FILEAPPENDER-INFO" class="ch.qos.logback.classic.AsyncAppender">
        <appender-ref ref="APPENDER-FILEAPPENDER-INFO" />
        <!-- 设置异步阻塞队列的大小,为了不丢失日志建议设置的大一些,单机压测时100000是没问题的,应该不用担心OOM -->
        <queueSize>10000</queueSize>
        <!-- 设置丢弃DEBUG、TRACE、INFO日志的阀值,不丢失 -->
        <discardingThreshold>0</discardingThreshold>
        <!-- 设置队列入队时非阻塞,当队列满时会直接丢弃日志,但是对性能提升极大 -->
        <neverBlock>${IS_IMMEDIATEFLUSH}</neverBlock>
    </appender>

    <!-- 将项目本次运行DEBUG日志同步输出到文件,会自动清空文件中上一次的日志 -->
    <appender name="APPENDER-FILEAPPENDER-DEBUG" class="ch.qos.logback.core.FileAppender">
        <!-- 过滤器,只记录 info 级别以上的日志 -->
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <level>DEBUG</level>
        </filter>
        <!-- 写入的日志文件名,可以使相对目录也可以是绝对目录,如果上级目录不存在则自动创建 -->
        <file>${LOG_PATH}/${MACHINE_IP}/${VIRTUAL_IP}/${LOG_NAME}-debug.log</file>
        <!-- 如果为true表示日志被追加到文件结尾,如果是false表示清空文件 -->
        <append>${IS_APPEND}</append>
        <!--立即刷新,设置成false可以提高日志吞吐量-->
        <immediateFlush>true</immediateFlush>
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <pattern>${FILE_LOG_PATTERN}</pattern>
            <charset>${ENCODING}</charset>
        </encoder>
    </appender>

    <!-- 将项目本次运行DEBUG日志异步输出到文件,会自动清空文件中上一次的日志 -->
    <appender name="ASYNC-APPENDER-FILEAPPENDER-DEBUG" class="ch.qos.logback.classic.AsyncAppender">
        <appender-ref ref="APPENDER-FILEAPPENDER-DEBUG" />
        <!-- 设置异步阻塞队列的大小,为了不丢失日志建议设置的大一些,单机压测时100000是没问题的,应该不用担心OOM -->
        <queueSize>10000</queueSize>
        <!-- 设置丢弃DEBUG、TRACE、INFO日志的阀值,不丢失 -->
        <discardingThreshold>0</discardingThreshold>
        <!-- 设置队列入队时非阻塞,当队列满时会直接丢弃日志,但是对性能提升极大 -->
        <neverBlock>true</neverBlock>
    </appender>

    <!-- 将项目本次运行ERROR日志同步输出到文件,会自动清空文件中上一次的日志 -->
    <appender name="APPENDER-FILEAPPENDER-ERROR" class="ch.qos.logback.core.FileAppender">
        <!-- 过滤器,只记录 info 级别以上的日志 -->
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <level>DEBUG</level>
        </filter>
        <!-- 写入的日志文件名,可以使相对目录也可以是绝对目录,如果上级目录不存在则自动创建 -->
        <file>${LOG_PATH}/${MACHINE_IP}/${VIRTUAL_IP}/${LOG_NAME}-error.log</file>
        <!-- 如果为true表示日志被追加到文件结尾,如果是false表示清空文件 -->
        <append>${IS_APPEND}</append>
        <!--立即刷新,设置成false可以提高日志吞吐量-->
        <immediateFlush>${IS_IMMEDIATEFLUSH}</immediateFlush>
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <pattern>${FILE_LOG_PATTERN}</pattern>
            <charset>${ENCODING}</charset>
        </encoder>
    </appender>

    <!-- 将项目本次运行ERROR日志异步输出到文件,会自动清空文件中上一次的日志 -->
    <appender name="ASYNC-APPENDER-FILEAPPENDER-ERROR" class="ch.qos.logback.classic.AsyncAppender">
        <appender-ref ref="APPENDER-FILEAPPENDER-ERROR" />
        <!-- 设置异步阻塞队列的大小,为了不丢失日志建议设置的大一些,单机压测时100000是没问题的,应该不用担心OOM -->
        <queueSize>10000</queueSize>
        <!-- 设置丢弃DEBUG、TRACE、INFO日志的阀值,不丢失 -->
        <discardingThreshold>0</discardingThreshold>
        <!-- 设置队列入队时非阻塞,当队列满时会直接丢弃日志,但是对性能提升极大 -->
        <neverBlock>true</neverBlock>
    </appender>
    <!--输出到文件:结束-->


    <!--滚动输出到文件(按照天保存):开始-->
    <!-- 将项目本次运行INFO日志同步输出到文件,按照每天生成日志文件,会自动拼接上一次日志 -->
    <appender name="APPENDER-ROLLINGFILEAPPENDER-INFO" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <!-- 过滤器,只记录 info 级别以上的日志 -->
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <level>INFO</level>
        </filter>
        <!--立即刷新,设置成false可以提高日志吞吐量-->
        <immediateFlush>false</immediateFlush>
        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
            <!-- 日志文件输出的文件名:
                %d:可以包含一个Java.text.SimpleDateFormat指定的时间格式
                %i:自增数字
            -->
            <fileNamePattern>${LOG_PATH}/${MACHINE_IP}/${VIRTUAL_IP}/HISTORY/${LOG_NAME}-info-%d{yyyy-MM-dd}-index%i.log</fileNamePattern>
            <!-- 日志文件保存历史数量:控制保留的归档文件的最大数量,如果超出数量就删除旧文件 -->
            <maxHistory>10</maxHistory>
            <!-- 文件大小超过100MB归档 -->
            <maxFileSize>20MB</maxFileSize>
        </rollingPolicy>
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <pattern>${FILE_LOG_PATTERN}</pattern>
            <charset>${ENCODING}</charset>
        </encoder>
    </appender>

    <!-- 将项目本次运行INFO日志异步输出到文件,按照每天生成日志文件,会自动拼接上一次日志 -->
    <appender name="ASYNC-APPENDER-ROLLINGFILEAPPENDER-INFO" class="ch.qos.logback.classic.AsyncAppender">
        <appender-ref ref="APPENDER-ROLLINGFILEAPPENDER-INFO" />
        <!-- 设置异步阻塞队列的大小,为了不丢失日志建议设置的大一些,单机压测时100000是没问题的,应该不用担心OOM -->
        <queueSize>10000</queueSize>
        <!-- 设置丢弃DEBUG、TRACE、INFO日志的阀值,不丢失 -->
        <discardingThreshold>0</discardingThreshold>
        <!-- 设置队列入队时非阻塞,当队列满时会直接丢弃日志,但是对性能提升极大 -->
        <neverBlock>true</neverBlock>
    </appender>

    <!-- 将项目本次运行DEBUG日志同步输出到文件,按照每天生成日志文件,会自动拼接上一次日志 -->
    <appender name="APPENDER-ROLLINGFILEAPPENDER-DEBUG" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <!-- 过滤器,只记录 info 级别以上的日志 -->
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <level>DEBUG</level>
        </filter>
        <!--立即刷新,设置成false可以提高日志吞吐量-->
        <immediateFlush>false</immediateFlush>
        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
            <!-- 日志文件输出的文件名:
                %d:可以包含一个Java.text.SimpleDateFormat指定的时间格式
                %i:自增数字
            -->
            <fileNamePattern>${LOG_PATH}/${MACHINE_IP}/${VIRTUAL_IP}/HISTORY/${LOG_NAME}-debug-%d{yyyy-MM-dd}-index%i.log</fileNamePattern>
            <!-- 日志文件保存历史数量:控制保留的归档文件的最大数量,如果超出数量就删除旧文件 -->
            <maxHistory>10</maxHistory>
            <!-- 文件大小超过100MB归档 -->
            <maxFileSize>20MB</maxFileSize>
        </rollingPolicy>
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <pattern>${FILE_LOG_PATTERN}</pattern>
            <charset>${ENCODING}</charset>
        </encoder>
    </appender>

    <!-- 将项目本次运行DEBUG日志异步输出到文件,按照每天生成日志文件,会自动拼接上一次日志 -->
    <appender name="ASYNC-APPENDER-ROLLINGFILEAPPENDER-DEBUG" class="ch.qos.logback.classic.AsyncAppender">
        <appender-ref ref="APPENDER-ROLLINGFILEAPPENDER-DEBUG" />
        <!-- 设置异步阻塞队列的大小,为了不丢失日志建议设置的大一些,单机压测时100000是没问题的,应该不用担心OOM -->
        <queueSize>10000</queueSize>
        <!-- 设置丢弃DEBUG、TRACE、INFO日志的阀值,不丢失 -->
        <discardingThreshold>0</discardingThreshold>
        <!-- 设置队列入队时非阻塞,当队列满时会直接丢弃日志,但是对性能提升极大 -->
        <neverBlock>true</neverBlock>
    </appender>

    <!-- 将项目本次运行ERROR日志同步输出到文件,按照每天生成日志文件,会自动拼接上一次日志 -->
    <appender name="APPENDER-ROLLINGFILEAPPENDER-ERROR" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <!-- 过滤器,只记录error级别的日志 -->
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>ERROR</level>
            <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>
        <!--立即刷新,设置成false可以提高日志吞吐量-->
        <immediateFlush>false</immediateFlush>
        <!-- 每天生成一个日志文件,保存30天的日志文件 -->
        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
            <!-- 日志文件输出的文件名:按天回滚 daily -->
            <fileNamePattern>${LOG_PATH}/${MACHINE_IP}/${VIRTUAL_IP}/HISTORY/${LOG_NAME}-error-%d{yyyy-MM-dd}-index%i.log</fileNamePattern>
            <!-- 日志文件保留天数 -->
            <maxHistory>10</maxHistory>
            <!-- 文件大小超过100MB归档 -->
            <maxFileSize>20MB</maxFileSize>
        </rollingPolicy>
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <pattern>${FILE_LOG_PATTERN}</pattern>
            <charset>utf8</charset>
        </encoder>
    </appender>

    <appender name="ASYNC-APPENDER-ROLLINGFILEAPPENDER-ERROR" class="ch.qos.logback.classic.AsyncAppender">
        <appender-ref ref="APPENDER-ROLLINGFILEAPPENDER-ERROR" />
        <!-- 设置异步阻塞队列的大小,为了不丢失日志建议设置的大一些,单机压测时100000是没问题的,应该不用担心OOM -->
        <queueSize>10000</queueSize>
        <!-- 设置丢弃DEBUG、TRACE、INFO日志的阀值,不丢失 -->
        <discardingThreshold>0</discardingThreshold>
        <!-- 设置队列入队时非阻塞,当队列满时会直接丢弃日志,但是对性能提升极大 -->
        <neverBlock>true</neverBlock>
    </appender>
    <!--滚动输出到文件(按照天保存):结束-->

    <!--输出到LOGSTASH:开始-->
    <!-- 将项目本次运行ERROR日志同步输出到文件,按照每天生成日志文件,会自动拼接上一次日志 -->
    <appender name="APPENDER-LOGSTASH" class="net.logstash.logback.appender.LogstashTcpSocketAppender">
        <!--  logstash服务器地址-->
        <destination>${LOGSTASH_HOST}</destination>
        <encoder class="net.logstash.logback.encoder.LoggingEventCompositeJsonEncoder">
            <providers>
                <pattern>
                    <pattern>
                        {
                        "appName":"${INDEX_NAME}",
                        "machineIp":"${MACHINE_IP}",
                        "virtualIp":"${VIRTUAL_IP}",
                        "serviceName":"${LOG_NAME}",
                        "timestamp": "%date{\"yyyy-MM-dd'T'HH:mm:ss,SSSZ\"}",
                        "logLevel":"%level",
                        "message":"%msg%n",
                        "traceId": "%X{X-B3-TraceId:-}",
                        "spanId": "%X{X-B3-SpanId:-}",
                        "spanExport": "%X{X-Span-Export:-}"
                        }
                    </pattern>
                </pattern>
            </providers>
        </encoder>
    </appender>
    <appender name="ASYNC-APPENDER-LOGSTASH" class="ch.qos.logback.classic.AsyncAppender">
        <appender-ref ref="APPENDER-LOGSTASH" />
        <!-- 设置异步阻塞队列的大小,为了不丢失日志建议设置的大一些,单机压测时100000是没问题的,应该不用担心OOM -->
        <queueSize>10000</queueSize>
        <!-- 设置丢弃DEBUG、TRACE、INFO日志的阀值,不丢失 -->
        <discardingThreshold>0</discardingThreshold>
        <!-- 设置队列入队时非阻塞,当队列满时会直接丢弃日志,但是对性能提升极大 -->
        <neverBlock>true</neverBlock>
    </appender>
    <!--输出到logstash:结束-->

    <!--
        开发环境日志级别为DEBUG
        level:用来设置打印级别
        五个常用打印级别从低至高依次为TRACE、DEBUG、INFO、WARN、ERROR
    -->
    <springProfile name="dev">
        <root>
            <!--输出到控制台-->
            <appender-ref ref="STDOUT"/>
            <!--异步非滚动输出到文件-->
            <appender-ref ref="ASYNC-APPENDER-FILEAPPENDER-INFO"/>
            <appender-ref ref="ASYNC-APPENDER-FILEAPPENDER-DEBUG"/>
            <appender-ref ref="ASYNC-APPENDER-FILEAPPENDER-ERROR"/>
            <!--异步滚动输出到文件:dev环境不开启-->
<!--            <appender-ref ref="ASYNC-APPENDER-ROLLINGFILEAPPENDER-INFO"/>-->
<!--            <appender-ref ref="ASYNC-APPENDER-ROLLINGFILEAPPENDER-DEBUG"/>-->
<!--            <appender-ref ref="ASYNC-APPENDER-ROLLINGFILEAPPENDER-ERROR"/>-->
            <!--异步滚动输出到logstash-->
            <appender-ref ref="ASYNC-APPENDER-LOGSTASH"/>
        </root>
    </springProfile>

    <!-- 测试环境日志级别为INFO -->
    <springProfile name="test">
        <root>
            <!--输出到控制台-->
            <appender-ref ref="STDOUT"/>
            <!--异步非滚动输出到文件-->
            <appender-ref ref="ASYNC-APPENDER-FILEAPPENDER-INFO"/>
            <appender-ref ref="ASYNC-APPENDER-FILEAPPENDER-DEBUG"/>
            <appender-ref ref="ASYNC-APPENDER-FILEAPPENDER-ERROR"/>
            <!--异步滚动输出到文件:test环境不开启-->
<!--            <appender-ref ref="ASYNC-APPENDER-ROLLINGFILEAPPENDER-INFO"/>-->
<!--            <appender-ref ref="ASYNC-APPENDER-ROLLINGFILEAPPENDER-DEBUG"/>-->
<!--            <appender-ref ref="ASYNC-APPENDER-ROLLINGFILEAPPENDER-ERROR"/>-->
            <!--异步滚动输出到logstash-->
            <appender-ref ref="ASYNC-APPENDER-LOGSTASH"/>
        </root>
    </springProfile>

    <!-- 生产环境日志级别为INFO -->
    <springProfile name="prod">
        <root>
            <!--输出到控制台-->
            <appender-ref ref="STDOUT"/>
            <!--异步非滚动输出到文件-->
            <appender-ref ref="ASYNC-APPENDER-FILEAPPENDER-INFO"/>
            <appender-ref ref="ASYNC-APPENDER-FILEAPPENDER-DEBUG"/>
            <appender-ref ref="ASYNC-APPENDER-FILEAPPENDER-ERROR"/>
            <!--异步滚动输出到文件-->
            <appender-ref ref="ASYNC-APPENDER-ROLLINGFILEAPPENDER-INFO"/>
            <appender-ref ref="ASYNC-APPENDER-ROLLINGFILEAPPENDER-DEBUG"/>
            <appender-ref ref="ASYNC-APPENDER-ROLLINGFILEAPPENDER-ERROR"/>
            <!--异步滚动输出到logstash-->
            <appender-ref ref="ASYNC-APPENDER-LOGSTASH"/>
        </root>
    </springProfile>

    <!-- rancher环境日志级别为INFO -->
    <springProfile name="rancher">
        <root>
            <!--输出到控制台-->
            <appender-ref ref="STDOUT"/>
            <!--异步非滚动输出到文件-->
            <appender-ref ref="ASYNC-APPENDER-FILEAPPENDER-INFO"/>
            <appender-ref ref="ASYNC-APPENDER-FILEAPPENDER-DEBUG"/>
            <appender-ref ref="ASYNC-APPENDER-FILEAPPENDER-ERROR"/>
            <!--异步滚动输出到文件-->
            <appender-ref ref="ASYNC-APPENDER-ROLLINGFILEAPPENDER-INFO"/>
            <appender-ref ref="ASYNC-APPENDER-ROLLINGFILEAPPENDER-DEBUG"/>
            <appender-ref ref="ASYNC-APPENDER-ROLLINGFILEAPPENDER-ERROR"/>
            <!--异步滚动输出到logstash-->
            <appender-ref ref="ASYNC-APPENDER-LOGSTASH"/>
        </root>
    </springProfile>
</configuration>

prod环境配置文件
application.yml
#设置spring项目运行的环境
spring:
  profiles:
    active: '@profile.active@'


application-prod.yml
server:
  port: 80
spring:
  application:
    name: SPRINGCLOUD-BASIC-SAMPLE-CONSUMER-LOADBALANCE-OPENFEIGN-DYNAMIC-SERVICENAME-ORDER80-PROD #注意:服务名不要出现_
  devtools:
    restart:
      enabled: true
  logging: #Spring运行日志配置
    level: info

eureka:
  client:
    register-with-eureka: true  #表示是否将自己注册进EurekaServer默认为true。
    fetchRegistry: true  #是否从EurekaServer抓取已有的注册信息,默认为true。服务提供端是单节点无所谓,是集群必须设置为true才能配合ribbon使用负载均衡,否则报异常No instances available for SPRINGCLOUD-PROVIDER-PAYMENT-SERVICE-CLUSTER
    service-url:
      #单机版
      defaultZone: http://192.168.0.4:7005/eureka
      #集群版
      #defaultZone: http://eureka7002:7002/eureka,http://eureka7003:7003/eureka,http://eureka7004:7004/eureka
  instance:
    instance-id: ${spring.application.name} #Eureka仪表盘中Instances currently registered with Eureka.Status显示的内容
    #当前微服务所在部署机器ip
    ip-address: 192.168.0.4
    prefer-ip-address: false #访问路径可以显示IP地址,点击Eureka仪表盘中Instances currently registered with Eureka.Status显示的内容地址栏是否显示IP地址

#服务提供端信息
service:
  provider:
    provider-1: &provider-1 SPRINGCLOUD-BASIC-SAMPLE-PROVIDER-PAYMENT-SERVICE-CLUSTER-${spring.profiles.active}  #服务提供端名称

#某个/某些服务的Ribbon配置
*provider-1: #服务提供端名称
  ribbon:
    NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule  #Ribbon负载均衡规则类所在的路径,自带七种规则,也可以是自定位规则的类所在的路径
#对OpenFeign进行单独配置
feign:
  client:
    config:
      #这里填具体的服务名称(也可以填default,表示对所有服务生效)
      *provider-1:  #服务提供端名称
        #connectTimeout和readTimeout这两个得一起配置才会生效
        connectTimeout: 5000  #指的是建立连接所用的时间,适用于网络状况正常的情况下,两端连接所用的时间
        readTimeout: 5000   #指的是建立连接后从服务器读取到可用资源所用的时间

#配置文件修改说明-------------------------------------------------:开始
#注意:不同的部署环境需要修改的配置
#   1.${logback.path}  #修改日志存放位置,Linxu为/,Windows为\
#       修改原因: Linux和Windows目录结构不同
#配置文件修改说明-------------------------------------------------:结束

#自定义日志配置文件路径
logging:
  config: classpath:logback-custom.xml
  path: /logs #所有日志存放在位置,加上\方便Linux环境下配置
  level:
    root: info #全局日志输出级别
    org.openatom.springcloud.services.PaymentServiceOpenFeign: debug  #OpenFeign增强日志配置,OpenFeign日志以什么级别监控哪个接口
    org.openatom.springcloud.services.PaymentServiceOpenFeignDynamicFeignClientFactory: debug  #OpenFeign增强日志配置,OpenFeign日志以什么级别监控哪个接口

logback:
  log-name: ${spring.application.name}
  append: false #是否启用append(追加到已经存在日志文件尾部),true:重启项目会追加新日志到之前日志,false:重启项目会清空之前的日志
  immediate-flush: true #是否启用immediateFlush(立即刷新),true:重启项目自动追加,false:重启项目会情况之前的日志
  deploy-machine-ip: ${eureka.instance.ip-address} #当前微服务所在部署机器ip

#logstash相关配置:开始
logstash:
  host: 192.168.0.4:5044 # logstash地址
  index: '@project.parent.artifactId@' # es中index名称
#logstash相关配置:结束

#actuator监控:开始
#通过下面的配置启用所有的监控端点,默认情况下,这些端点是禁用的;
management:
  endpoints:
    web:
      exposure:
        include: '*'
    enabled-by-default: true
  endpoint:
    health:
      show-details: always # 访问/actuator/health时,显示详细信息,而不是仅仅显示"status": "UP"
    # 日志文件路径:特别注意,此处无法配置日志文件路径,因为rancher会生成虚拟ip,这个虚拟ip是无法在这里获取的,
    #           但是虚拟ip是路径的一部分,所以这个路径无法拼接出来,所以这里无法配置日志文件路径
    #logfile:
    #  external-file:
#actuator监控:结束

logback-custom.xml
<?xml version="1.0" encoding="UTF-8"?>

<!--
    scan: 当此属性设置为true时,配置文件如果发生改变,将会被重新加载,默认值为true。
    scanPeriod: 设置监测配置文件是否有修改的时间间隔,如果没有给出时间单位,默认单位是毫秒。当scan为true时,此属性生效。默认的时间间隔为1分钟。
    debug: 当此属性设置为true时,将打印出logback内部日志信息,实时查看logback运行状态。默认值为false。
-->
<!-- 输出logback内部日志信息,每隔30s判断一下配置文件有没有更新,若更新,则重新加载 -->
<configuration scan="true" scanPeriod="30 seconds" debug="false">
    <!--从java代码中获取虚拟ip的值-->
    <!--获取当前微服务部署虚拟IP,如rancher为当前微服务分配的ip-->
    <define name="VIRTUAL_IP" class="org.openatom.springcloud.config.VirtualIpConfig"/>

    <!--从Spring容器中获取配置(Spring配置文件加载顺序:bootstrap.yml->logback.xml->application.yml)-->
    <!--获取当前微服务部署机器ip-->
    <springProperty name="MACHINE_IP" scope="context" source="logback.deploy-machine-ip"/>
    <!--应用名称-->
    <springProperty name="LOG_NAME" scope="context" source="logback.log-name"/>
    <!--是否启用append-->
    <springProperty name="IS_APPEND" scope="context" source="logback.append"/>
    <!--是否启用立即刷新-->
    <springProperty name="IS_IMMEDIATEFLUSH" scope="context" source="logback.immediate-flush"/>
    <springProperty name="LOG_PATH" scope="context" source="logging.path"/>
    <!--logstash地址-->
    <springProperty name="LOGSTASH_HOST" scope="context" source="logstash.host"/>
    <!--索引名称-->
    <springProperty name="INDEX_NAME" scope="context" source="logstash.index"/>


    <!-- name:变量的名称,可以随意起名,但建议名字要简明直译;value:变量的值;在配置文件中,我们可以用 ${} 的方式来使用,将变量引入到其他节点中去。-->
    <!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度 %msg:日志消息,%n是换行符-->
    <!--控制台日志输出预选样式-->
    <property name="CONSOLE_LOG_PATTERN_1" value="%red(%d{yyyy-MM-dd HH:mm:ss.SSS}) %green([%thread]) [machineIp:${MACHINE_IP} virtualIp:${VIRTUAL_IP}] [TraceId:%X{X-B3-TraceId:-} SpanId:%X{X-B3-SpanId:-} %highlight(%-5level) %boldMagenta(%logger{10}): %cyan(%msg%n)"/>
    <property name="CONSOLE_LOG_PATTERN_2" value="%yellow(%date{yyyy-MM-dd HH:mm:ss}) [machineIp:${MACHINE_IP} virtualIp:${VIRTUAL_IP}] [TraceId:%X{X-B3-TraceId:-} SpanId:%X{X-B3-SpanId:-} %highlight([%-5level]) %green(%logger) %msg%n"/>
    <property name="CONSOLE_LOG_PATTERN_3" value="%date{yyyy-MM-dd HH:mm:ss} [machineIp:${MACHINE_IP} virtualIp:${VIRTUAL_IP}] [TraceId:%X{X-B3-TraceId:-} SpanId:%X{X-B3-SpanId:-} Span-Export:%X{X-Span-Export:-}]  %green(%-5level) %boldMagenta(${PID:-}) -- [%+20thread] %cyan(%logger{20}) %line       : %msg%n"/>
    <!--文件中日志输出预选样式-->
    <property name="FILE_LOG_PATTERN_1" value="%d{yyyyMMdd:HH:mm:ss.SSS} [machineIp:${MACHINE_IP} virtualIp:${VIRTUAL_IP}] [TraceId:%X{X-B3-TraceId:-} SpanId:%X{X-B3-SpanId:-} [%thread] %-5level  %msg%n"/>

    <!--控制台日志输出格式-->
    <property name="CONSOLE_LOG_PATTERN" value="${CONSOLE_LOG_PATTERN_3}"/>
    <!--文件中日志输出格式-->
    <property name="FILE_LOG_PATTERN" value="${FILE_LOG_PATTERN_1}"/>
    <!--日志名称-->
    <!--定义默认日志输出级别-->
    <property name="LOG_OUTPUT_LEVEL" value="${LOG_LEVEL}" />
    <!--定义默认日志输出编码-->
    <property name="ENCODING" value="UTF-8" />

    <!-- 控制台输出:开始 -->
    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
        <!-- 用来设置日志的输入格式,使用“%+转换符”的方式,如果要输出”%”则必须使用”\”进行转义。-->
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <!-- 格式化输出:https://logback.qos.ch/manual/layouts.html
                 %d 表示日期,
                 %thread 表示线程名,
                 %level 日志级别从左显示5个字符宽度,
                 %t 线程名
                 %file:%line 文件名+行号,
                 %m 日志消息,%n是换行符
                 %X{traceId}:自定义设置的参数,后面会说。
            -->
            <pattern>${CONSOLE_LOG_PATTERN}</pattern>
            <charset>${ENCODING}</charset>
        </encoder>
    </appender>
    <!-- 控制台输出:结束 -->

    <!--输出到文件:开始-->
    <!-- 将项目本次运行INFO日志同步输出到文件,会自动清空文件中上一次的日志 -->
    <appender name="APPENDER-FILEAPPENDER-INFO" class="ch.qos.logback.core.FileAppender">
        <!-- 过滤器,只记录 info 级别以上的日志 -->
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <level>INFO</level>
        </filter>
        <!-- 写入的日志文件名,可以使相对目录也可以是绝对目录,如果上级目录不存在则自动创建 -->
        <file>${LOG_PATH}/${MACHINE_IP}/${VIRTUAL_IP}/${LOG_NAME}-info.log</file>
        <!-- 如果为true表示日志被追加到文件结尾,如果是false表示清空文件 -->
        <append>${IS_APPEND}</append>
        <!--立即刷新,设置成false可以提高日志吞吐量-->
        <immediateFlush>${IS_IMMEDIATEFLUSH}</immediateFlush>
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <pattern>${FILE_LOG_PATTERN}</pattern>
            <charset>${ENCODING}</charset>
        </encoder>
    </appender>

    <!-- 将项目本次运行INFO日志异步输出到文件,会自动清空文件中上一次的日志 -->
    <appender name="ASYNC-APPENDER-FILEAPPENDER-INFO" class="ch.qos.logback.classic.AsyncAppender">
        <appender-ref ref="APPENDER-FILEAPPENDER-INFO" />
        <!-- 设置异步阻塞队列的大小,为了不丢失日志建议设置的大一些,单机压测时100000是没问题的,应该不用担心OOM -->
        <queueSize>10000</queueSize>
        <!-- 设置丢弃DEBUG、TRACE、INFO日志的阀值,不丢失 -->
        <discardingThreshold>0</discardingThreshold>
        <!-- 设置队列入队时非阻塞,当队列满时会直接丢弃日志,但是对性能提升极大 -->
        <neverBlock>${IS_IMMEDIATEFLUSH}</neverBlock>
    </appender>

    <!-- 将项目本次运行DEBUG日志同步输出到文件,会自动清空文件中上一次的日志 -->
    <appender name="APPENDER-FILEAPPENDER-DEBUG" class="ch.qos.logback.core.FileAppender">
        <!-- 过滤器,只记录 info 级别以上的日志 -->
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <level>DEBUG</level>
        </filter>
        <!-- 写入的日志文件名,可以使相对目录也可以是绝对目录,如果上级目录不存在则自动创建 -->
        <file>${LOG_PATH}/${MACHINE_IP}/${VIRTUAL_IP}/${LOG_NAME}-debug.log</file>
        <!-- 如果为true表示日志被追加到文件结尾,如果是false表示清空文件 -->
        <append>${IS_APPEND}</append>
        <!--立即刷新,设置成false可以提高日志吞吐量-->
        <immediateFlush>true</immediateFlush>
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <pattern>${FILE_LOG_PATTERN}</pattern>
            <charset>${ENCODING}</charset>
        </encoder>
    </appender>

    <!-- 将项目本次运行DEBUG日志异步输出到文件,会自动清空文件中上一次的日志 -->
    <appender name="ASYNC-APPENDER-FILEAPPENDER-DEBUG" class="ch.qos.logback.classic.AsyncAppender">
        <appender-ref ref="APPENDER-FILEAPPENDER-DEBUG" />
        <!-- 设置异步阻塞队列的大小,为了不丢失日志建议设置的大一些,单机压测时100000是没问题的,应该不用担心OOM -->
        <queueSize>10000</queueSize>
        <!-- 设置丢弃DEBUG、TRACE、INFO日志的阀值,不丢失 -->
        <discardingThreshold>0</discardingThreshold>
        <!-- 设置队列入队时非阻塞,当队列满时会直接丢弃日志,但是对性能提升极大 -->
        <neverBlock>true</neverBlock>
    </appender>

    <!-- 将项目本次运行ERROR日志同步输出到文件,会自动清空文件中上一次的日志 -->
    <appender name="APPENDER-FILEAPPENDER-ERROR" class="ch.qos.logback.core.FileAppender">
        <!-- 过滤器,只记录 info 级别以上的日志 -->
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <level>DEBUG</level>
        </filter>
        <!-- 写入的日志文件名,可以使相对目录也可以是绝对目录,如果上级目录不存在则自动创建 -->
        <file>${LOG_PATH}/${MACHINE_IP}/${VIRTUAL_IP}/${LOG_NAME}-error.log</file>
        <!-- 如果为true表示日志被追加到文件结尾,如果是false表示清空文件 -->
        <append>${IS_APPEND}</append>
        <!--立即刷新,设置成false可以提高日志吞吐量-->
        <immediateFlush>${IS_IMMEDIATEFLUSH}</immediateFlush>
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <pattern>${FILE_LOG_PATTERN}</pattern>
            <charset>${ENCODING}</charset>
        </encoder>
    </appender>

    <!-- 将项目本次运行ERROR日志异步输出到文件,会自动清空文件中上一次的日志 -->
    <appender name="ASYNC-APPENDER-FILEAPPENDER-ERROR" class="ch.qos.logback.classic.AsyncAppender">
        <appender-ref ref="APPENDER-FILEAPPENDER-ERROR" />
        <!-- 设置异步阻塞队列的大小,为了不丢失日志建议设置的大一些,单机压测时100000是没问题的,应该不用担心OOM -->
        <queueSize>10000</queueSize>
        <!-- 设置丢弃DEBUG、TRACE、INFO日志的阀值,不丢失 -->
        <discardingThreshold>0</discardingThreshold>
        <!-- 设置队列入队时非阻塞,当队列满时会直接丢弃日志,但是对性能提升极大 -->
        <neverBlock>true</neverBlock>
    </appender>
    <!--输出到文件:结束-->


    <!--滚动输出到文件(按照天保存):开始-->
    <!-- 将项目本次运行INFO日志同步输出到文件,按照每天生成日志文件,会自动拼接上一次日志 -->
    <appender name="APPENDER-ROLLINGFILEAPPENDER-INFO" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <!-- 过滤器,只记录 info 级别以上的日志 -->
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <level>INFO</level>
        </filter>
        <!--立即刷新,设置成false可以提高日志吞吐量-->
        <immediateFlush>false</immediateFlush>
        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
            <!-- 日志文件输出的文件名:
                %d:可以包含一个Java.text.SimpleDateFormat指定的时间格式
                %i:自增数字
            -->
            <fileNamePattern>${LOG_PATH}/${MACHINE_IP}/${VIRTUAL_IP}/HISTORY/${LOG_NAME}-info-%d{yyyy-MM-dd}-index%i.log</fileNamePattern>
            <!-- 日志文件保存历史数量:控制保留的归档文件的最大数量,如果超出数量就删除旧文件 -->
            <maxHistory>10</maxHistory>
            <!-- 文件大小超过100MB归档 -->
            <maxFileSize>20MB</maxFileSize>
        </rollingPolicy>
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <pattern>${FILE_LOG_PATTERN}</pattern>
            <charset>${ENCODING}</charset>
        </encoder>
    </appender>

    <!-- 将项目本次运行INFO日志异步输出到文件,按照每天生成日志文件,会自动拼接上一次日志 -->
    <appender name="ASYNC-APPENDER-ROLLINGFILEAPPENDER-INFO" class="ch.qos.logback.classic.AsyncAppender">
        <appender-ref ref="APPENDER-ROLLINGFILEAPPENDER-INFO" />
        <!-- 设置异步阻塞队列的大小,为了不丢失日志建议设置的大一些,单机压测时100000是没问题的,应该不用担心OOM -->
        <queueSize>10000</queueSize>
        <!-- 设置丢弃DEBUG、TRACE、INFO日志的阀值,不丢失 -->
        <discardingThreshold>0</discardingThreshold>
        <!-- 设置队列入队时非阻塞,当队列满时会直接丢弃日志,但是对性能提升极大 -->
        <neverBlock>true</neverBlock>
    </appender>

    <!-- 将项目本次运行DEBUG日志同步输出到文件,按照每天生成日志文件,会自动拼接上一次日志 -->
    <appender name="APPENDER-ROLLINGFILEAPPENDER-DEBUG" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <!-- 过滤器,只记录 info 级别以上的日志 -->
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <level>DEBUG</level>
        </filter>
        <!--立即刷新,设置成false可以提高日志吞吐量-->
        <immediateFlush>false</immediateFlush>
        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
            <!-- 日志文件输出的文件名:
                %d:可以包含一个Java.text.SimpleDateFormat指定的时间格式
                %i:自增数字
            -->
            <fileNamePattern>${LOG_PATH}/${MACHINE_IP}/${VIRTUAL_IP}/HISTORY/${LOG_NAME}-debug-%d{yyyy-MM-dd}-index%i.log</fileNamePattern>
            <!-- 日志文件保存历史数量:控制保留的归档文件的最大数量,如果超出数量就删除旧文件 -->
            <maxHistory>10</maxHistory>
            <!-- 文件大小超过100MB归档 -->
            <maxFileSize>20MB</maxFileSize>
        </rollingPolicy>
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <pattern>${FILE_LOG_PATTERN}</pattern>
            <charset>${ENCODING}</charset>
        </encoder>
    </appender>

    <!-- 将项目本次运行DEBUG日志异步输出到文件,按照每天生成日志文件,会自动拼接上一次日志 -->
    <appender name="ASYNC-APPENDER-ROLLINGFILEAPPENDER-DEBUG" class="ch.qos.logback.classic.AsyncAppender">
        <appender-ref ref="APPENDER-ROLLINGFILEAPPENDER-DEBUG" />
        <!-- 设置异步阻塞队列的大小,为了不丢失日志建议设置的大一些,单机压测时100000是没问题的,应该不用担心OOM -->
        <queueSize>10000</queueSize>
        <!-- 设置丢弃DEBUG、TRACE、INFO日志的阀值,不丢失 -->
        <discardingThreshold>0</discardingThreshold>
        <!-- 设置队列入队时非阻塞,当队列满时会直接丢弃日志,但是对性能提升极大 -->
        <neverBlock>true</neverBlock>
    </appender>

    <!-- 将项目本次运行ERROR日志同步输出到文件,按照每天生成日志文件,会自动拼接上一次日志 -->
    <appender name="APPENDER-ROLLINGFILEAPPENDER-ERROR" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <!-- 过滤器,只记录error级别的日志 -->
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>ERROR</level>
            <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>
        <!--立即刷新,设置成false可以提高日志吞吐量-->
        <immediateFlush>false</immediateFlush>
        <!-- 每天生成一个日志文件,保存30天的日志文件 -->
        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
            <!-- 日志文件输出的文件名:按天回滚 daily -->
            <fileNamePattern>${LOG_PATH}/${MACHINE_IP}/${VIRTUAL_IP}/HISTORY/${LOG_NAME}-error-%d{yyyy-MM-dd}-index%i.log</fileNamePattern>
            <!-- 日志文件保留天数 -->
            <maxHistory>10</maxHistory>
            <!-- 文件大小超过100MB归档 -->
            <maxFileSize>20MB</maxFileSize>
        </rollingPolicy>
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <pattern>${FILE_LOG_PATTERN}</pattern>
            <charset>utf8</charset>
        </encoder>
    </appender>

    <appender name="ASYNC-APPENDER-ROLLINGFILEAPPENDER-ERROR" class="ch.qos.logback.classic.AsyncAppender">
        <appender-ref ref="APPENDER-ROLLINGFILEAPPENDER-ERROR" />
        <!-- 设置异步阻塞队列的大小,为了不丢失日志建议设置的大一些,单机压测时100000是没问题的,应该不用担心OOM -->
        <queueSize>10000</queueSize>
        <!-- 设置丢弃DEBUG、TRACE、INFO日志的阀值,不丢失 -->
        <discardingThreshold>0</discardingThreshold>
        <!-- 设置队列入队时非阻塞,当队列满时会直接丢弃日志,但是对性能提升极大 -->
        <neverBlock>true</neverBlock>
    </appender>
    <!--滚动输出到文件(按照天保存):结束-->

    <!--输出到LOGSTASH:开始-->
    <!-- 将项目本次运行ERROR日志同步输出到文件,按照每天生成日志文件,会自动拼接上一次日志 -->
    <appender name="APPENDER-LOGSTASH" class="net.logstash.logback.appender.LogstashTcpSocketAppender">
        <!--  logstash服务器地址-->
        <destination>${LOGSTASH_HOST}</destination>
        <encoder class="net.logstash.logback.encoder.LoggingEventCompositeJsonEncoder">
            <providers>
                <pattern>
                    <pattern>
                        {
                        "appName":"${INDEX_NAME}",
                        "machineIp":"${MACHINE_IP}",
                        "virtualIp":"${VIRTUAL_IP}",
                        "serviceName":"${LOG_NAME}",
                        "timestamp": "%date{\"yyyy-MM-dd'T'HH:mm:ss,SSSZ\"}",
                        "logLevel":"%level",
                        "message":"%msg%n",
                        "traceId": "%X{X-B3-TraceId:-}",
                        "spanId": "%X{X-B3-SpanId:-}",
                        "spanExport": "%X{X-Span-Export:-}"
                        }
                    </pattern>
                </pattern>
            </providers>
        </encoder>
    </appender>
    <appender name="ASYNC-APPENDER-LOGSTASH" class="ch.qos.logback.classic.AsyncAppender">
        <appender-ref ref="APPENDER-LOGSTASH" />
        <!-- 设置异步阻塞队列的大小,为了不丢失日志建议设置的大一些,单机压测时100000是没问题的,应该不用担心OOM -->
        <queueSize>10000</queueSize>
        <!-- 设置丢弃DEBUG、TRACE、INFO日志的阀值,不丢失 -->
        <discardingThreshold>0</discardingThreshold>
        <!-- 设置队列入队时非阻塞,当队列满时会直接丢弃日志,但是对性能提升极大 -->
        <neverBlock>true</neverBlock>
    </appender>
    <!--输出到logstash:结束-->

    <!--
        开发环境日志级别为DEBUG
        level:用来设置打印级别
        五个常用打印级别从低至高依次为TRACE、DEBUG、INFO、WARN、ERROR
    -->
    <springProfile name="dev">
        <root>
            <!--输出到控制台-->
            <appender-ref ref="STDOUT"/>
            <!--异步非滚动输出到文件-->
            <appender-ref ref="ASYNC-APPENDER-FILEAPPENDER-INFO"/>
            <appender-ref ref="ASYNC-APPENDER-FILEAPPENDER-DEBUG"/>
            <appender-ref ref="ASYNC-APPENDER-FILEAPPENDER-ERROR"/>
            <!--异步滚动输出到文件:dev环境不开启-->
<!--            <appender-ref ref="ASYNC-APPENDER-ROLLINGFILEAPPENDER-INFO"/>-->
<!--            <appender-ref ref="ASYNC-APPENDER-ROLLINGFILEAPPENDER-DEBUG"/>-->
<!--            <appender-ref ref="ASYNC-APPENDER-ROLLINGFILEAPPENDER-ERROR"/>-->
            <!--异步滚动输出到logstash-->
            <appender-ref ref="ASYNC-APPENDER-LOGSTASH"/>
        </root>
    </springProfile>

    <!-- 测试环境日志级别为INFO -->
    <springProfile name="test">
        <root>
            <!--输出到控制台-->
            <appender-ref ref="STDOUT"/>
            <!--异步非滚动输出到文件-->
            <appender-ref ref="ASYNC-APPENDER-FILEAPPENDER-INFO"/>
            <appender-ref ref="ASYNC-APPENDER-FILEAPPENDER-DEBUG"/>
            <appender-ref ref="ASYNC-APPENDER-FILEAPPENDER-ERROR"/>
            <!--异步滚动输出到文件:test环境不开启-->
<!--            <appender-ref ref="ASYNC-APPENDER-ROLLINGFILEAPPENDER-INFO"/>-->
<!--            <appender-ref ref="ASYNC-APPENDER-ROLLINGFILEAPPENDER-DEBUG"/>-->
<!--            <appender-ref ref="ASYNC-APPENDER-ROLLINGFILEAPPENDER-ERROR"/>-->
            <!--异步滚动输出到logstash-->
            <appender-ref ref="ASYNC-APPENDER-LOGSTASH"/>
        </root>
    </springProfile>

    <!-- 生产环境日志级别为INFO -->
    <springProfile name="prod">
        <root>
            <!--输出到控制台-->
            <appender-ref ref="STDOUT"/>
            <!--异步非滚动输出到文件-->
            <appender-ref ref="ASYNC-APPENDER-FILEAPPENDER-INFO"/>
            <appender-ref ref="ASYNC-APPENDER-FILEAPPENDER-DEBUG"/>
            <appender-ref ref="ASYNC-APPENDER-FILEAPPENDER-ERROR"/>
            <!--异步滚动输出到文件-->
            <appender-ref ref="ASYNC-APPENDER-ROLLINGFILEAPPENDER-INFO"/>
            <appender-ref ref="ASYNC-APPENDER-ROLLINGFILEAPPENDER-DEBUG"/>
            <appender-ref ref="ASYNC-APPENDER-ROLLINGFILEAPPENDER-ERROR"/>
            <!--异步滚动输出到logstash-->
            <appender-ref ref="ASYNC-APPENDER-LOGSTASH"/>
        </root>
    </springProfile>

    <!-- rancher环境日志级别为INFO -->
    <springProfile name="rancher">
        <root>
            <!--输出到控制台-->
            <appender-ref ref="STDOUT"/>
            <!--异步非滚动输出到文件-->
            <appender-ref ref="ASYNC-APPENDER-FILEAPPENDER-INFO"/>
            <appender-ref ref="ASYNC-APPENDER-FILEAPPENDER-DEBUG"/>
            <appender-ref ref="ASYNC-APPENDER-FILEAPPENDER-ERROR"/>
            <!--异步滚动输出到文件-->
            <appender-ref ref="ASYNC-APPENDER-ROLLINGFILEAPPENDER-INFO"/>
            <appender-ref ref="ASYNC-APPENDER-ROLLINGFILEAPPENDER-DEBUG"/>
            <appender-ref ref="ASYNC-APPENDER-ROLLINGFILEAPPENDER-ERROR"/>
            <!--异步滚动输出到logstash-->
            <appender-ref ref="ASYNC-APPENDER-LOGSTASH"/>
        </root>
    </springProfile>
</configuration>

rancher环境配置文件
application.yml
#设置spring项目运行的环境
spring:
  profiles:
    active: '@profile.active@'


application-rancher.yml
server:
  port: 80
spring:
  application:
    name: SPRINGCLOUD-BASIC-SAMPLE-CONSUMER-LOADBALANCE-OPENFEIGN-DYNAMIC-SERVICENAME-ORDER80-RANCHER #注意:服务名不要出现_
  devtools:
    restart:
      enabled: true
  logging: #Spring运行日志配置
    level: info

eureka:
  client:
    register-with-eureka: true  #表示是否将自己注册进EurekaServer默认为true。
    fetchRegistry: true  #是否从EurekaServer抓取已有的注册信息,默认为true。服务提供端是单节点无所谓,是集群必须设置为true才能配合ribbon使用负载均衡,否则报异常No instances available for SPRINGCLOUD-PROVIDER-PAYMENT-SERVICE-CLUSTER
    service-url:
      #单机版
      defaultZone: http://192.168.0.4:7005/eureka
      #集群版
      #defaultZone: http://eureka7002:7002/eureka,http://eureka7003:7003/eureka,http://eureka7004:7004/eureka
  instance:
    #使用rancher扩容不能配置instance-id,否则会出问题
    #instance-id: ${spring.application.name} #Eureka仪表盘中Instances currently registered with Eureka.Status显示的内容
    #使用rancher扩容不能配置iip-address,否则会出问题
    #ip-address: 192.168.0.4
    prefer-ip-address: false #访问路径可以显示IP地址,点击Eureka仪表盘中Instances currently registered with Eureka.Status显示的内容地址栏是否显示IP地址

#服务提供端信息
service:
  provider:
    provider-1: &provider-1 SPRINGCLOUD-BASIC-SAMPLE-PROVIDER-PAYMENT-SERVICE-CLUSTER-${spring.profiles.active}  #服务提供端名称

#某个/某些服务的Ribbon配置
*provider-1: #服务提供端名称
  ribbon:
    NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule  #Ribbon负载均衡规则类所在的路径,自带七种规则,也可以是自定位规则的类所在的路径
#对OpenFeign进行单独配置
feign:
  client:
    config:
      #这里填具体的服务名称(也可以填default,表示对所有服务生效)
      *provider-1:  #服务提供端名称
        #connectTimeout和readTimeout这两个得一起配置才会生效
        connectTimeout: 5000  #指的是建立连接所用的时间,适用于网络状况正常的情况下,两端连接所用的时间
        readTimeout: 5000   #指的是建立连接后从服务器读取到可用资源所用的时间

#配置文件修改说明-------------------------------------------------:开始
#注意:不同的部署环境需要修改的配置
#   1.${logback.path}  #修改日志存放位置,Linxu为/,Windows为\
#       修改原因: Linux和Windows目录结构不同
#配置文件修改说明-------------------------------------------------:结束

#自定义日志配置文件路径
logging:
  config: classpath:logback-custom.xml
  path: /logs #所有日志存放在位置,加上\方便Linux环境下配置
  level:
    root: info #全局日志输出级别
  org.openatom.springcloud.services.PaymentServiceOpenFeign: debug  #OpenFeign增强日志配置,OpenFeign日志以什么级别监控哪个接口
  org.openatom.springcloud.services.PaymentServiceOpenFeignDynamicFeignClientFactory: debug  #OpenFeign增强日志配置,OpenFeign日志以什么级别监控哪个接口

logback:
  log-name: ${spring.application.name}
  append: false #是否启用append(追加到已经存在日志文件尾部),true:重启项目会追加新日志到之前日志,false:重启项目会清空之前的日志
  immediate-flush: true #是否启用immediateFlush(立即刷新),true:重启项目自动追加,false:重启项目会情况之前的日志
  deploy-machine-ip: 192.168.0.4 #当前微服务所在部署机器ip

#logstash相关配置:开始
logstash:
  host: 192.168.0.4:5044 # logstash地址
  index: '@project.parent.artifactId@' # es中index名称
#logstash相关配置:结束

#actuator监控:开始
#通过下面的配置启用所有的监控端点,默认情况下,这些端点是禁用的;
management:
  endpoints:
    web:
      exposure:
        include: '*'
    enabled-by-default: true
  endpoint:
    health:
      show-details: always # 访问/actuator/health时,显示详细信息,而不是仅仅显示"status": "UP"
    # 日志文件路径:特别注意,此处无法配置日志文件路径,因为rancher会生成虚拟ip,这个虚拟ip是无法在这里获取的,
    #           但是虚拟ip是路径的一部分,所以这个路径无法拼接出来,所以这里无法配置日志文件路径
    #logfile:
    #  external-file:
#actuator监控:结束

logback-custom.xml
<?xml version="1.0" encoding="UTF-8"?>

<!--
    scan: 当此属性设置为true时,配置文件如果发生改变,将会被重新加载,默认值为true。
    scanPeriod: 设置监测配置文件是否有修改的时间间隔,如果没有给出时间单位,默认单位是毫秒。当scan为true时,此属性生效。默认的时间间隔为1分钟。
    debug: 当此属性设置为true时,将打印出logback内部日志信息,实时查看logback运行状态。默认值为false。
-->
<!-- 输出logback内部日志信息,每隔30s判断一下配置文件有没有更新,若更新,则重新加载 -->
<configuration scan="true" scanPeriod="30 seconds" debug="false">
    <!--从java代码中获取虚拟ip的值-->
    <!--获取当前微服务部署虚拟IP,如rancher为当前微服务分配的ip-->
    <define name="VIRTUAL_IP" class="org.openatom.springcloud.config.VirtualIpConfig"/>

    <!--从Spring容器中获取配置(Spring配置文件加载顺序:bootstrap.yml->logback.xml->application.yml)-->
    <!--获取当前微服务部署机器ip-->
    <springProperty name="MACHINE_IP" scope="context" source="logback.deploy-machine-ip"/>
    <!--应用名称-->
    <springProperty name="LOG_NAME" scope="context" source="logback.log-name"/>
    <!--是否启用append-->
    <springProperty name="IS_APPEND" scope="context" source="logback.append"/>
    <!--是否启用立即刷新-->
    <springProperty name="IS_IMMEDIATEFLUSH" scope="context" source="logback.immediate-flush"/>
    <springProperty name="LOG_PATH" scope="context" source="logging.path"/>
    <!--logstash地址-->
    <springProperty name="LOGSTASH_HOST" scope="context" source="logstash.host"/>
    <!--索引名称-->
    <springProperty name="INDEX_NAME" scope="context" source="logstash.index"/>


    <!-- name:变量的名称,可以随意起名,但建议名字要简明直译;value:变量的值;在配置文件中,我们可以用 ${} 的方式来使用,将变量引入到其他节点中去。-->
    <!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度 %msg:日志消息,%n是换行符-->
    <!--控制台日志输出预选样式-->
    <property name="CONSOLE_LOG_PATTERN_1" value="%red(%d{yyyy-MM-dd HH:mm:ss.SSS}) %green([%thread]) [machineIp:${MACHINE_IP} virtualIp:${VIRTUAL_IP}] [TraceId:%X{X-B3-TraceId:-} SpanId:%X{X-B3-SpanId:-} %highlight(%-5level) %boldMagenta(%logger{10}): %cyan(%msg%n)"/>
    <property name="CONSOLE_LOG_PATTERN_2" value="%yellow(%date{yyyy-MM-dd HH:mm:ss}) [machineIp:${MACHINE_IP} virtualIp:${VIRTUAL_IP}] [TraceId:%X{X-B3-TraceId:-} SpanId:%X{X-B3-SpanId:-} %highlight([%-5level]) %green(%logger) %msg%n"/>
    <property name="CONSOLE_LOG_PATTERN_3" value="%date{yyyy-MM-dd HH:mm:ss} [machineIp:${MACHINE_IP} virtualIp:${VIRTUAL_IP}] [TraceId:%X{X-B3-TraceId:-} SpanId:%X{X-B3-SpanId:-} Span-Export:%X{X-Span-Export:-}]  %green(%-5level) %boldMagenta(${PID:-}) -- [%+20thread] %cyan(%logger{20}) %line       : %msg%n"/>
    <!--文件中日志输出预选样式-->
    <property name="FILE_LOG_PATTERN_1" value="%d{yyyyMMdd:HH:mm:ss.SSS} [machineIp:${MACHINE_IP} virtualIp:${VIRTUAL_IP}] [TraceId:%X{X-B3-TraceId:-} SpanId:%X{X-B3-SpanId:-} [%thread] %-5level  %msg%n"/>

    <!--控制台日志输出格式-->
    <property name="CONSOLE_LOG_PATTERN" value="${CONSOLE_LOG_PATTERN_3}"/>
    <!--文件中日志输出格式-->
    <property name="FILE_LOG_PATTERN" value="${FILE_LOG_PATTERN_1}"/>
    <!--日志名称-->
    <!--定义默认日志输出级别-->
    <property name="LOG_OUTPUT_LEVEL" value="${LOG_LEVEL}" />
    <!--定义默认日志输出编码-->
    <property name="ENCODING" value="UTF-8" />

    <!-- 控制台输出:开始 -->
    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
        <!-- 用来设置日志的输入格式,使用“%+转换符”的方式,如果要输出”%”则必须使用”\”进行转义。-->
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <!-- 格式化输出:https://logback.qos.ch/manual/layouts.html
                 %d 表示日期,
                 %thread 表示线程名,
                 %level 日志级别从左显示5个字符宽度,
                 %t 线程名
                 %file:%line 文件名+行号,
                 %m 日志消息,%n是换行符
                 %X{traceId}:自定义设置的参数,后面会说。
            -->
            <pattern>${CONSOLE_LOG_PATTERN}</pattern>
            <charset>${ENCODING}</charset>
        </encoder>
    </appender>
    <!-- 控制台输出:结束 -->

    <!--输出到文件:开始-->
    <!-- 将项目本次运行INFO日志同步输出到文件,会自动清空文件中上一次的日志 -->
    <appender name="APPENDER-FILEAPPENDER-INFO" class="ch.qos.logback.core.FileAppender">
        <!-- 过滤器,只记录 info 级别以上的日志 -->
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <level>INFO</level>
        </filter>
        <!-- 写入的日志文件名,可以使相对目录也可以是绝对目录,如果上级目录不存在则自动创建 -->
        <file>${LOG_PATH}/${MACHINE_IP}/${VIRTUAL_IP}/${LOG_NAME}-info.log</file>
        <!-- 如果为true表示日志被追加到文件结尾,如果是false表示清空文件 -->
        <append>${IS_APPEND}</append>
        <!--立即刷新,设置成false可以提高日志吞吐量-->
        <immediateFlush>${IS_IMMEDIATEFLUSH}</immediateFlush>
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <pattern>${FILE_LOG_PATTERN}</pattern>
            <charset>${ENCODING}</charset>
        </encoder>
    </appender>

    <!-- 将项目本次运行INFO日志异步输出到文件,会自动清空文件中上一次的日志 -->
    <appender name="ASYNC-APPENDER-FILEAPPENDER-INFO" class="ch.qos.logback.classic.AsyncAppender">
        <appender-ref ref="APPENDER-FILEAPPENDER-INFO" />
        <!-- 设置异步阻塞队列的大小,为了不丢失日志建议设置的大一些,单机压测时100000是没问题的,应该不用担心OOM -->
        <queueSize>10000</queueSize>
        <!-- 设置丢弃DEBUG、TRACE、INFO日志的阀值,不丢失 -->
        <discardingThreshold>0</discardingThreshold>
        <!-- 设置队列入队时非阻塞,当队列满时会直接丢弃日志,但是对性能提升极大 -->
        <neverBlock>${IS_IMMEDIATEFLUSH}</neverBlock>
    </appender>

    <!-- 将项目本次运行DEBUG日志同步输出到文件,会自动清空文件中上一次的日志 -->
    <appender name="APPENDER-FILEAPPENDER-DEBUG" class="ch.qos.logback.core.FileAppender">
        <!-- 过滤器,只记录 info 级别以上的日志 -->
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <level>DEBUG</level>
        </filter>
        <!-- 写入的日志文件名,可以使相对目录也可以是绝对目录,如果上级目录不存在则自动创建 -->
        <file>${LOG_PATH}/${MACHINE_IP}/${VIRTUAL_IP}/${LOG_NAME}-debug.log</file>
        <!-- 如果为true表示日志被追加到文件结尾,如果是false表示清空文件 -->
        <append>${IS_APPEND}</append>
        <!--立即刷新,设置成false可以提高日志吞吐量-->
        <immediateFlush>true</immediateFlush>
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <pattern>${FILE_LOG_PATTERN}</pattern>
            <charset>${ENCODING}</charset>
        </encoder>
    </appender>

    <!-- 将项目本次运行DEBUG日志异步输出到文件,会自动清空文件中上一次的日志 -->
    <appender name="ASYNC-APPENDER-FILEAPPENDER-DEBUG" class="ch.qos.logback.classic.AsyncAppender">
        <appender-ref ref="APPENDER-FILEAPPENDER-DEBUG" />
        <!-- 设置异步阻塞队列的大小,为了不丢失日志建议设置的大一些,单机压测时100000是没问题的,应该不用担心OOM -->
        <queueSize>10000</queueSize>
        <!-- 设置丢弃DEBUG、TRACE、INFO日志的阀值,不丢失 -->
        <discardingThreshold>0</discardingThreshold>
        <!-- 设置队列入队时非阻塞,当队列满时会直接丢弃日志,但是对性能提升极大 -->
        <neverBlock>true</neverBlock>
    </appender>

    <!-- 将项目本次运行ERROR日志同步输出到文件,会自动清空文件中上一次的日志 -->
    <appender name="APPENDER-FILEAPPENDER-ERROR" class="ch.qos.logback.core.FileAppender">
        <!-- 过滤器,只记录 info 级别以上的日志 -->
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <level>DEBUG</level>
        </filter>
        <!-- 写入的日志文件名,可以使相对目录也可以是绝对目录,如果上级目录不存在则自动创建 -->
        <file>${LOG_PATH}/${MACHINE_IP}/${VIRTUAL_IP}/${LOG_NAME}-error.log</file>
        <!-- 如果为true表示日志被追加到文件结尾,如果是false表示清空文件 -->
        <append>${IS_APPEND}</append>
        <!--立即刷新,设置成false可以提高日志吞吐量-->
        <immediateFlush>${IS_IMMEDIATEFLUSH}</immediateFlush>
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <pattern>${FILE_LOG_PATTERN}</pattern>
            <charset>${ENCODING}</charset>
        </encoder>
    </appender>

    <!-- 将项目本次运行ERROR日志异步输出到文件,会自动清空文件中上一次的日志 -->
    <appender name="ASYNC-APPENDER-FILEAPPENDER-ERROR" class="ch.qos.logback.classic.AsyncAppender">
        <appender-ref ref="APPENDER-FILEAPPENDER-ERROR" />
        <!-- 设置异步阻塞队列的大小,为了不丢失日志建议设置的大一些,单机压测时100000是没问题的,应该不用担心OOM -->
        <queueSize>10000</queueSize>
        <!-- 设置丢弃DEBUG、TRACE、INFO日志的阀值,不丢失 -->
        <discardingThreshold>0</discardingThreshold>
        <!-- 设置队列入队时非阻塞,当队列满时会直接丢弃日志,但是对性能提升极大 -->
        <neverBlock>true</neverBlock>
    </appender>
    <!--输出到文件:结束-->


    <!--滚动输出到文件(按照天保存):开始-->
    <!-- 将项目本次运行INFO日志同步输出到文件,按照每天生成日志文件,会自动拼接上一次日志 -->
    <appender name="APPENDER-ROLLINGFILEAPPENDER-INFO" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <!-- 过滤器,只记录 info 级别以上的日志 -->
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <level>INFO</level>
        </filter>
        <!--立即刷新,设置成false可以提高日志吞吐量-->
        <immediateFlush>false</immediateFlush>
        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
            <!-- 日志文件输出的文件名:
                %d:可以包含一个Java.text.SimpleDateFormat指定的时间格式
                %i:自增数字
            -->
            <fileNamePattern>${LOG_PATH}/${MACHINE_IP}/${VIRTUAL_IP}/HISTORY/${LOG_NAME}-info-%d{yyyy-MM-dd}-index%i.log</fileNamePattern>
            <!-- 日志文件保存历史数量:控制保留的归档文件的最大数量,如果超出数量就删除旧文件 -->
            <maxHistory>10</maxHistory>
            <!-- 文件大小超过100MB归档 -->
            <maxFileSize>20MB</maxFileSize>
        </rollingPolicy>
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <pattern>${FILE_LOG_PATTERN}</pattern>
            <charset>${ENCODING}</charset>
        </encoder>
    </appender>

    <!-- 将项目本次运行INFO日志异步输出到文件,按照每天生成日志文件,会自动拼接上一次日志 -->
    <appender name="ASYNC-APPENDER-ROLLINGFILEAPPENDER-INFO" class="ch.qos.logback.classic.AsyncAppender">
        <appender-ref ref="APPENDER-ROLLINGFILEAPPENDER-INFO" />
        <!-- 设置异步阻塞队列的大小,为了不丢失日志建议设置的大一些,单机压测时100000是没问题的,应该不用担心OOM -->
        <queueSize>10000</queueSize>
        <!-- 设置丢弃DEBUG、TRACE、INFO日志的阀值,不丢失 -->
        <discardingThreshold>0</discardingThreshold>
        <!-- 设置队列入队时非阻塞,当队列满时会直接丢弃日志,但是对性能提升极大 -->
        <neverBlock>true</neverBlock>
    </appender>

    <!-- 将项目本次运行DEBUG日志同步输出到文件,按照每天生成日志文件,会自动拼接上一次日志 -->
    <appender name="APPENDER-ROLLINGFILEAPPENDER-DEBUG" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <!-- 过滤器,只记录 info 级别以上的日志 -->
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <level>DEBUG</level>
        </filter>
        <!--立即刷新,设置成false可以提高日志吞吐量-->
        <immediateFlush>false</immediateFlush>
        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
            <!-- 日志文件输出的文件名:
                %d:可以包含一个Java.text.SimpleDateFormat指定的时间格式
                %i:自增数字
            -->
            <fileNamePattern>${LOG_PATH}/${MACHINE_IP}/${VIRTUAL_IP}/HISTORY/${LOG_NAME}-debug-%d{yyyy-MM-dd}-index%i.log</fileNamePattern>
            <!-- 日志文件保存历史数量:控制保留的归档文件的最大数量,如果超出数量就删除旧文件 -->
            <maxHistory>10</maxHistory>
            <!-- 文件大小超过100MB归档 -->
            <maxFileSize>20MB</maxFileSize>
        </rollingPolicy>
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <pattern>${FILE_LOG_PATTERN}</pattern>
            <charset>${ENCODING}</charset>
        </encoder>
    </appender>

    <!-- 将项目本次运行DEBUG日志异步输出到文件,按照每天生成日志文件,会自动拼接上一次日志 -->
    <appender name="ASYNC-APPENDER-ROLLINGFILEAPPENDER-DEBUG" class="ch.qos.logback.classic.AsyncAppender">
        <appender-ref ref="APPENDER-ROLLINGFILEAPPENDER-DEBUG" />
        <!-- 设置异步阻塞队列的大小,为了不丢失日志建议设置的大一些,单机压测时100000是没问题的,应该不用担心OOM -->
        <queueSize>10000</queueSize>
        <!-- 设置丢弃DEBUG、TRACE、INFO日志的阀值,不丢失 -->
        <discardingThreshold>0</discardingThreshold>
        <!-- 设置队列入队时非阻塞,当队列满时会直接丢弃日志,但是对性能提升极大 -->
        <neverBlock>true</neverBlock>
    </appender>

    <!-- 将项目本次运行ERROR日志同步输出到文件,按照每天生成日志文件,会自动拼接上一次日志 -->
    <appender name="APPENDER-ROLLINGFILEAPPENDER-ERROR" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <!-- 过滤器,只记录error级别的日志 -->
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>ERROR</level>
            <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>
        <!--立即刷新,设置成false可以提高日志吞吐量-->
        <immediateFlush>false</immediateFlush>
        <!-- 每天生成一个日志文件,保存30天的日志文件 -->
        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
            <!-- 日志文件输出的文件名:按天回滚 daily -->
            <fileNamePattern>${LOG_PATH}/${MACHINE_IP}/${VIRTUAL_IP}/HISTORY/${LOG_NAME}-error-%d{yyyy-MM-dd}-index%i.log</fileNamePattern>
            <!-- 日志文件保留天数 -->
            <maxHistory>10</maxHistory>
            <!-- 文件大小超过100MB归档 -->
            <maxFileSize>20MB</maxFileSize>
        </rollingPolicy>
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <pattern>${FILE_LOG_PATTERN}</pattern>
            <charset>utf8</charset>
        </encoder>
    </appender>

    <appender name="ASYNC-APPENDER-ROLLINGFILEAPPENDER-ERROR" class="ch.qos.logback.classic.AsyncAppender">
        <appender-ref ref="APPENDER-ROLLINGFILEAPPENDER-ERROR" />
        <!-- 设置异步阻塞队列的大小,为了不丢失日志建议设置的大一些,单机压测时100000是没问题的,应该不用担心OOM -->
        <queueSize>10000</queueSize>
        <!-- 设置丢弃DEBUG、TRACE、INFO日志的阀值,不丢失 -->
        <discardingThreshold>0</discardingThreshold>
        <!-- 设置队列入队时非阻塞,当队列满时会直接丢弃日志,但是对性能提升极大 -->
        <neverBlock>true</neverBlock>
    </appender>
    <!--滚动输出到文件(按照天保存):结束-->

    <!--输出到LOGSTASH:开始-->
    <!-- 将项目本次运行ERROR日志同步输出到文件,按照每天生成日志文件,会自动拼接上一次日志 -->
    <appender name="APPENDER-LOGSTASH" class="net.logstash.logback.appender.LogstashTcpSocketAppender">
        <!--  logstash服务器地址-->
        <destination>${LOGSTASH_HOST}</destination>
        <encoder class="net.logstash.logback.encoder.LoggingEventCompositeJsonEncoder">
            <providers>
                <pattern>
                    <pattern>
                        {
                        "appName":"${INDEX_NAME}",
                        "machineIp":"${MACHINE_IP}",
                        "virtualIp":"${VIRTUAL_IP}",
                        "serviceName":"${LOG_NAME}",
                        "timestamp": "%date{\"yyyy-MM-dd'T'HH:mm:ss,SSSZ\"}",
                        "logLevel":"%level",
                        "message":"%msg%n",
                        "traceId": "%X{X-B3-TraceId:-}",
                        "spanId": "%X{X-B3-SpanId:-}",
                        "spanExport": "%X{X-Span-Export:-}"
                        }
                    </pattern>
                </pattern>
            </providers>
        </encoder>
    </appender>
    <appender name="ASYNC-APPENDER-LOGSTASH" class="ch.qos.logback.classic.AsyncAppender">
        <appender-ref ref="APPENDER-LOGSTASH" />
        <!-- 设置异步阻塞队列的大小,为了不丢失日志建议设置的大一些,单机压测时100000是没问题的,应该不用担心OOM -->
        <queueSize>10000</queueSize>
        <!-- 设置丢弃DEBUG、TRACE、INFO日志的阀值,不丢失 -->
        <discardingThreshold>0</discardingThreshold>
        <!-- 设置队列入队时非阻塞,当队列满时会直接丢弃日志,但是对性能提升极大 -->
        <neverBlock>true</neverBlock>
    </appender>
    <!--输出到logstash:结束-->

    <!--
        开发环境日志级别为DEBUG
        level:用来设置打印级别
        五个常用打印级别从低至高依次为TRACE、DEBUG、INFO、WARN、ERROR
    -->
    <springProfile name="dev">
        <root>
            <!--输出到控制台-->
            <appender-ref ref="STDOUT"/>
            <!--异步非滚动输出到文件-->
            <appender-ref ref="ASYNC-APPENDER-FILEAPPENDER-INFO"/>
            <appender-ref ref="ASYNC-APPENDER-FILEAPPENDER-DEBUG"/>
            <appender-ref ref="ASYNC-APPENDER-FILEAPPENDER-ERROR"/>
            <!--异步滚动输出到文件:dev环境不开启-->
<!--            <appender-ref ref="ASYNC-APPENDER-ROLLINGFILEAPPENDER-INFO"/>-->
<!--            <appender-ref ref="ASYNC-APPENDER-ROLLINGFILEAPPENDER-DEBUG"/>-->
<!--            <appender-ref ref="ASYNC-APPENDER-ROLLINGFILEAPPENDER-ERROR"/>-->
            <!--异步滚动输出到logstash-->
            <appender-ref ref="ASYNC-APPENDER-LOGSTASH"/>
        </root>
    </springProfile>

    <!-- 测试环境日志级别为INFO -->
    <springProfile name="test">
        <root>
            <!--输出到控制台-->
            <appender-ref ref="STDOUT"/>
            <!--异步非滚动输出到文件-->
            <appender-ref ref="ASYNC-APPENDER-FILEAPPENDER-INFO"/>
            <appender-ref ref="ASYNC-APPENDER-FILEAPPENDER-DEBUG"/>
            <appender-ref ref="ASYNC-APPENDER-FILEAPPENDER-ERROR"/>
            <!--异步滚动输出到文件:test环境不开启-->
<!--            <appender-ref ref="ASYNC-APPENDER-ROLLINGFILEAPPENDER-INFO"/>-->
<!--            <appender-ref ref="ASYNC-APPENDER-ROLLINGFILEAPPENDER-DEBUG"/>-->
<!--            <appender-ref ref="ASYNC-APPENDER-ROLLINGFILEAPPENDER-ERROR"/>-->
            <!--异步滚动输出到logstash-->
            <appender-ref ref="ASYNC-APPENDER-LOGSTASH"/>
        </root>
    </springProfile>

    <!-- 生产环境日志级别为INFO -->
    <springProfile name="prod">
        <root>
            <!--输出到控制台-->
            <appender-ref ref="STDOUT"/>
            <!--异步非滚动输出到文件-->
            <appender-ref ref="ASYNC-APPENDER-FILEAPPENDER-INFO"/>
            <appender-ref ref="ASYNC-APPENDER-FILEAPPENDER-DEBUG"/>
            <appender-ref ref="ASYNC-APPENDER-FILEAPPENDER-ERROR"/>
            <!--异步滚动输出到文件-->
            <appender-ref ref="ASYNC-APPENDER-ROLLINGFILEAPPENDER-INFO"/>
            <appender-ref ref="ASYNC-APPENDER-ROLLINGFILEAPPENDER-DEBUG"/>
            <appender-ref ref="ASYNC-APPENDER-ROLLINGFILEAPPENDER-ERROR"/>
            <!--异步滚动输出到logstash-->
            <appender-ref ref="ASYNC-APPENDER-LOGSTASH"/>
        </root>
    </springProfile>

    <!-- rancher环境日志级别为INFO -->
    <springProfile name="rancher">
        <root>
            <!--输出到控制台-->
            <appender-ref ref="STDOUT"/>
            <!--异步非滚动输出到文件-->
            <appender-ref ref="ASYNC-APPENDER-FILEAPPENDER-INFO"/>
            <appender-ref ref="ASYNC-APPENDER-FILEAPPENDER-DEBUG"/>
            <appender-ref ref="ASYNC-APPENDER-FILEAPPENDER-ERROR"/>
            <!--异步滚动输出到文件-->
            <appender-ref ref="ASYNC-APPENDER-ROLLINGFILEAPPENDER-INFO"/>
            <appender-ref ref="ASYNC-APPENDER-ROLLINGFILEAPPENDER-DEBUG"/>
            <appender-ref ref="ASYNC-APPENDER-ROLLINGFILEAPPENDER-ERROR"/>
            <!--异步滚动输出到logstash-->
            <appender-ref ref="ASYNC-APPENDER-LOGSTASH"/>
        </root>
    </springProfile>
</configuration>

test环境配置文件
application.yml
#设置spring项目运行的环境
spring:
  profiles:
    active: '@profile.active@'


application-test.yml
server:
  port: 80
spring:
  application:
    name: SPRINGCLOUD-BASIC-SAMPLE-CONSUMER-LOADBALANCE-OPENFEIGN-DYNAMIC-SERVICENAME-ORDER80-TEST #注意:服务名不要出现_
  devtools:
    restart:
      enabled: true
  logging: #Spring运行日志配置
    level: info

eureka:
  client:
    register-with-eureka: true  #表示是否将自己注册进EurekaServer默认为true。
    fetchRegistry: true  #是否从EurekaServer抓取已有的注册信息,默认为true。服务提供端是单节点无所谓,是集群必须设置为true才能配合ribbon使用负载均衡,否则报异常No instances available for SPRINGCLOUD-PROVIDER-PAYMENT-SERVICE-CLUSTER
    service-url:
      #单机版
      defaultZone: http://localhost:7005/eureka
      #集群版
      #defaultZone: http://eureka7002:7002/eureka,http://eureka7003:7003/eureka,http://eureka7004:7004/eureka
  instance:
    instance-id: ${spring.application.name} #Eureka仪表盘中Instances currently registered with Eureka.Status显示的内容
    #当前微服务所在部署机器ip
    ip-address: localhost
    prefer-ip-address: false #访问路径可以显示IP地址,点击Eureka仪表盘中Instances currently registered with Eureka.Status显示的内容地址栏是否显示IP地址

#服务提供端信息
service:
  provider:
    provider-1: &provider-1 SPRINGCLOUD-BASIC-SAMPLE-PROVIDER-PAYMENT-SERVICE-CLUSTER-${spring.profiles.active}  #服务提供端名称

#某个/某些服务的Ribbon配置
*provider-1: #服务提供端名称
  ribbon:
    NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule  #Ribbon负载均衡规则类所在的路径,自带七种规则,也可以是自定位规则的类所在的路径
#对OpenFeign进行单独配置
feign:
  client:
    config:
      #这里填具体的服务名称(也可以填default,表示对所有服务生效)
      *provider-1:  #服务提供端名称
        #connectTimeout和readTimeout这两个得一起配置才会生效
        connectTimeout: 5000  #指的是建立连接所用的时间,适用于网络状况正常的情况下,两端连接所用的时间
        readTimeout: 5000   #指的是建立连接后从服务器读取到可用资源所用的时间

#配置文件修改说明-------------------------------------------------:开始
#注意:不同的部署环境需要修改的配置
#   1.${logback.path}  #修改日志存放位置,Linxu为/,Windows为\
#       修改原因: Linux和Windows目录结构不同
#配置文件修改说明-------------------------------------------------:结束

#自定义日志配置文件路径
logging:
  config: classpath:logback-custom.xml
  path: D:\repository\workspace\IDEA\PERSONAL\springcloud-eureka\log\ #所有日志存放在位置,加上\方便Linux环境下配置
  level:
    root: info #全局日志输出级别
  org.openatom.springcloud.services.PaymentServiceOpenFeign: debug  #OpenFeign增强日志配置,OpenFeign日志以什么级别监控哪个接口
  org.openatom.springcloud.services.PaymentServiceOpenFeignDynamicFeignClientFactory: debug  #OpenFeign增强日志配置,OpenFeign日志以什么级别监控哪个接口

logback:
  log-name: ${spring.application.name}
  append: false #是否启用append(追加到已经存在日志文件尾部),true:重启项目会追加新日志到之前日志,false:重启项目会清空之前的日志
  immediate-flush: true #是否启用immediateFlush(立即刷新),true:重启项目自动追加,false:重启项目会情况之前的日志
  deploy-machine-ip: ${eureka.instance.ip-address} #当前微服务所在部署机器ip

#logstash相关配置:开始
logstash:
  host: 192.168.0.4:5044 # logstash地址
  index: '@project.parent.artifactId@' # es中index名称
#logstash相关配置:结束

#actuator监控:开始
#通过下面的配置启用所有的监控端点,默认情况下,这些端点是禁用的;
management:
  endpoints:
    web:
      exposure:
        include: '*'
    enabled-by-default: true
  endpoint:
    health:
      show-details: always # 访问/actuator/health时,显示详细信息,而不是仅仅显示"status": "UP"
    # 日志文件路径:特别注意,此处无法配置日志文件路径,因为rancher会生成虚拟ip,这个虚拟ip是无法在这里获取的,
    #           但是虚拟ip是路径的一部分,所以这个路径无法拼接出来,所以这里无法配置日志文件路径
    #logfile:
    #  external-file:
#actuator监控:结束

logback-custom.xml
<?xml version="1.0" encoding="UTF-8"?>

<!--
    scan: 当此属性设置为true时,配置文件如果发生改变,将会被重新加载,默认值为true。
    scanPeriod: 设置监测配置文件是否有修改的时间间隔,如果没有给出时间单位,默认单位是毫秒。当scan为true时,此属性生效。默认的时间间隔为1分钟。
    debug: 当此属性设置为true时,将打印出logback内部日志信息,实时查看logback运行状态。默认值为false。
-->
<!-- 输出logback内部日志信息,每隔30s判断一下配置文件有没有更新,若更新,则重新加载 -->
<configuration scan="true" scanPeriod="30 seconds" debug="false">
    <!--从java代码中获取虚拟ip的值-->
    <!--获取当前微服务部署虚拟IP,如rancher为当前微服务分配的ip-->
    <define name="VIRTUAL_IP" class="org.openatom.springcloud.config.VirtualIpConfig"/>

    <!--从Spring容器中获取配置(Spring配置文件加载顺序:bootstrap.yml->logback.xml->application.yml)-->
    <!--获取当前微服务部署机器ip-->
    <springProperty name="MACHINE_IP" scope="context" source="logback.deploy-machine-ip"/>
    <!--应用名称-->
    <springProperty name="LOG_NAME" scope="context" source="logback.log-name"/>
    <!--是否启用append-->
    <springProperty name="IS_APPEND" scope="context" source="logback.append"/>
    <!--是否启用立即刷新-->
    <springProperty name="IS_IMMEDIATEFLUSH" scope="context" source="logback.immediate-flush"/>
    <springProperty name="LOG_PATH" scope="context" source="logging.path"/>
    <!--logstash地址-->
    <springProperty name="LOGSTASH_HOST" scope="context" source="logstash.host"/>
    <!--索引名称-->
    <springProperty name="INDEX_NAME" scope="context" source="logstash.index"/>


    <!-- name:变量的名称,可以随意起名,但建议名字要简明直译;value:变量的值;在配置文件中,我们可以用 ${} 的方式来使用,将变量引入到其他节点中去。-->
    <!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度 %msg:日志消息,%n是换行符-->
    <!--控制台日志输出预选样式-->
    <property name="CONSOLE_LOG_PATTERN_1" value="%red(%d{yyyy-MM-dd HH:mm:ss.SSS}) %green([%thread]) [machineIp:${MACHINE_IP} virtualIp:${VIRTUAL_IP}] [TraceId:%X{X-B3-TraceId:-} SpanId:%X{X-B3-SpanId:-} %highlight(%-5level) %boldMagenta(%logger{10}): %cyan(%msg%n)"/>
    <property name="CONSOLE_LOG_PATTERN_2" value="%yellow(%date{yyyy-MM-dd HH:mm:ss}) [machineIp:${MACHINE_IP} virtualIp:${VIRTUAL_IP}] [TraceId:%X{X-B3-TraceId:-} SpanId:%X{X-B3-SpanId:-} %highlight([%-5level]) %green(%logger) %msg%n"/>
    <property name="CONSOLE_LOG_PATTERN_3" value="%date{yyyy-MM-dd HH:mm:ss} [machineIp:${MACHINE_IP} virtualIp:${VIRTUAL_IP}] [TraceId:%X{X-B3-TraceId:-} SpanId:%X{X-B3-SpanId:-} Span-Export:%X{X-Span-Export:-}]  %green(%-5level) %boldMagenta(${PID:-}) -- [%+20thread] %cyan(%logger{20}) %line       : %msg%n"/>
    <!--文件中日志输出预选样式-->
    <property name="FILE_LOG_PATTERN_1" value="%d{yyyyMMdd:HH:mm:ss.SSS} [machineIp:${MACHINE_IP} virtualIp:${VIRTUAL_IP}] [TraceId:%X{X-B3-TraceId:-} SpanId:%X{X-B3-SpanId:-} [%thread] %-5level  %msg%n"/>

    <!--控制台日志输出格式-->
    <property name="CONSOLE_LOG_PATTERN" value="${CONSOLE_LOG_PATTERN_3}"/>
    <!--文件中日志输出格式-->
    <property name="FILE_LOG_PATTERN" value="${FILE_LOG_PATTERN_1}"/>
    <!--日志名称-->
    <!--定义默认日志输出级别-->
    <property name="LOG_OUTPUT_LEVEL" value="${LOG_LEVEL}" />
    <!--定义默认日志输出编码-->
    <property name="ENCODING" value="UTF-8" />

    <!-- 控制台输出:开始 -->
    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
        <!-- 用来设置日志的输入格式,使用“%+转换符”的方式,如果要输出”%”则必须使用”\”进行转义。-->
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <!-- 格式化输出:https://logback.qos.ch/manual/layouts.html
                 %d 表示日期,
                 %thread 表示线程名,
                 %level 日志级别从左显示5个字符宽度,
                 %t 线程名
                 %file:%line 文件名+行号,
                 %m 日志消息,%n是换行符
                 %X{traceId}:自定义设置的参数,后面会说。
            -->
            <pattern>${CONSOLE_LOG_PATTERN}</pattern>
            <charset>${ENCODING}</charset>
        </encoder>
    </appender>
    <!-- 控制台输出:结束 -->

    <!--输出到文件:开始-->
    <!-- 将项目本次运行INFO日志同步输出到文件,会自动清空文件中上一次的日志 -->
    <appender name="APPENDER-FILEAPPENDER-INFO" class="ch.qos.logback.core.FileAppender">
        <!-- 过滤器,只记录 info 级别以上的日志 -->
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <level>INFO</level>
        </filter>
        <!-- 写入的日志文件名,可以使相对目录也可以是绝对目录,如果上级目录不存在则自动创建 -->
        <file>${LOG_PATH}/${MACHINE_IP}/${VIRTUAL_IP}/${LOG_NAME}-info.log</file>
        <!-- 如果为true表示日志被追加到文件结尾,如果是false表示清空文件 -->
        <append>${IS_APPEND}</append>
        <!--立即刷新,设置成false可以提高日志吞吐量-->
        <immediateFlush>${IS_IMMEDIATEFLUSH}</immediateFlush>
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <pattern>${FILE_LOG_PATTERN}</pattern>
            <charset>${ENCODING}</charset>
        </encoder>
    </appender>

    <!-- 将项目本次运行INFO日志异步输出到文件,会自动清空文件中上一次的日志 -->
    <appender name="ASYNC-APPENDER-FILEAPPENDER-INFO" class="ch.qos.logback.classic.AsyncAppender">
        <appender-ref ref="APPENDER-FILEAPPENDER-INFO" />
        <!-- 设置异步阻塞队列的大小,为了不丢失日志建议设置的大一些,单机压测时100000是没问题的,应该不用担心OOM -->
        <queueSize>10000</queueSize>
        <!-- 设置丢弃DEBUG、TRACE、INFO日志的阀值,不丢失 -->
        <discardingThreshold>0</discardingThreshold>
        <!-- 设置队列入队时非阻塞,当队列满时会直接丢弃日志,但是对性能提升极大 -->
        <neverBlock>${IS_IMMEDIATEFLUSH}</neverBlock>
    </appender>

    <!-- 将项目本次运行DEBUG日志同步输出到文件,会自动清空文件中上一次的日志 -->
    <appender name="APPENDER-FILEAPPENDER-DEBUG" class="ch.qos.logback.core.FileAppender">
        <!-- 过滤器,只记录 info 级别以上的日志 -->
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <level>DEBUG</level>
        </filter>
        <!-- 写入的日志文件名,可以使相对目录也可以是绝对目录,如果上级目录不存在则自动创建 -->
        <file>${LOG_PATH}/${MACHINE_IP}/${VIRTUAL_IP}/${LOG_NAME}-debug.log</file>
        <!-- 如果为true表示日志被追加到文件结尾,如果是false表示清空文件 -->
        <append>${IS_APPEND}</append>
        <!--立即刷新,设置成false可以提高日志吞吐量-->
        <immediateFlush>true</immediateFlush>
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <pattern>${FILE_LOG_PATTERN}</pattern>
            <charset>${ENCODING}</charset>
        </encoder>
    </appender>

    <!-- 将项目本次运行DEBUG日志异步输出到文件,会自动清空文件中上一次的日志 -->
    <appender name="ASYNC-APPENDER-FILEAPPENDER-DEBUG" class="ch.qos.logback.classic.AsyncAppender">
        <appender-ref ref="APPENDER-FILEAPPENDER-DEBUG" />
        <!-- 设置异步阻塞队列的大小,为了不丢失日志建议设置的大一些,单机压测时100000是没问题的,应该不用担心OOM -->
        <queueSize>10000</queueSize>
        <!-- 设置丢弃DEBUG、TRACE、INFO日志的阀值,不丢失 -->
        <discardingThreshold>0</discardingThreshold>
        <!-- 设置队列入队时非阻塞,当队列满时会直接丢弃日志,但是对性能提升极大 -->
        <neverBlock>true</neverBlock>
    </appender>

    <!-- 将项目本次运行ERROR日志同步输出到文件,会自动清空文件中上一次的日志 -->
    <appender name="APPENDER-FILEAPPENDER-ERROR" class="ch.qos.logback.core.FileAppender">
        <!-- 过滤器,只记录 info 级别以上的日志 -->
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <level>DEBUG</level>
        </filter>
        <!-- 写入的日志文件名,可以使相对目录也可以是绝对目录,如果上级目录不存在则自动创建 -->
        <file>${LOG_PATH}/${MACHINE_IP}/${VIRTUAL_IP}/${LOG_NAME}-error.log</file>
        <!-- 如果为true表示日志被追加到文件结尾,如果是false表示清空文件 -->
        <append>${IS_APPEND}</append>
        <!--立即刷新,设置成false可以提高日志吞吐量-->
        <immediateFlush>${IS_IMMEDIATEFLUSH}</immediateFlush>
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <pattern>${FILE_LOG_PATTERN}</pattern>
            <charset>${ENCODING}</charset>
        </encoder>
    </appender>

    <!-- 将项目本次运行ERROR日志异步输出到文件,会自动清空文件中上一次的日志 -->
    <appender name="ASYNC-APPENDER-FILEAPPENDER-ERROR" class="ch.qos.logback.classic.AsyncAppender">
        <appender-ref ref="APPENDER-FILEAPPENDER-ERROR" />
        <!-- 设置异步阻塞队列的大小,为了不丢失日志建议设置的大一些,单机压测时100000是没问题的,应该不用担心OOM -->
        <queueSize>10000</queueSize>
        <!-- 设置丢弃DEBUG、TRACE、INFO日志的阀值,不丢失 -->
        <discardingThreshold>0</discardingThreshold>
        <!-- 设置队列入队时非阻塞,当队列满时会直接丢弃日志,但是对性能提升极大 -->
        <neverBlock>true</neverBlock>
    </appender>
    <!--输出到文件:结束-->


    <!--滚动输出到文件(按照天保存):开始-->
    <!-- 将项目本次运行INFO日志同步输出到文件,按照每天生成日志文件,会自动拼接上一次日志 -->
    <appender name="APPENDER-ROLLINGFILEAPPENDER-INFO" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <!-- 过滤器,只记录 info 级别以上的日志 -->
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <level>INFO</level>
        </filter>
        <!--立即刷新,设置成false可以提高日志吞吐量-->
        <immediateFlush>false</immediateFlush>
        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
            <!-- 日志文件输出的文件名:
                %d:可以包含一个Java.text.SimpleDateFormat指定的时间格式
                %i:自增数字
            -->
            <fileNamePattern>${LOG_PATH}/${MACHINE_IP}/${VIRTUAL_IP}/HISTORY/${LOG_NAME}-info-%d{yyyy-MM-dd}-index%i.log</fileNamePattern>
            <!-- 日志文件保存历史数量:控制保留的归档文件的最大数量,如果超出数量就删除旧文件 -->
            <maxHistory>10</maxHistory>
            <!-- 文件大小超过100MB归档 -->
            <maxFileSize>20MB</maxFileSize>
        </rollingPolicy>
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <pattern>${FILE_LOG_PATTERN}</pattern>
            <charset>${ENCODING}</charset>
        </encoder>
    </appender>

    <!-- 将项目本次运行INFO日志异步输出到文件,按照每天生成日志文件,会自动拼接上一次日志 -->
    <appender name="ASYNC-APPENDER-ROLLINGFILEAPPENDER-INFO" class="ch.qos.logback.classic.AsyncAppender">
        <appender-ref ref="APPENDER-ROLLINGFILEAPPENDER-INFO" />
        <!-- 设置异步阻塞队列的大小,为了不丢失日志建议设置的大一些,单机压测时100000是没问题的,应该不用担心OOM -->
        <queueSize>10000</queueSize>
        <!-- 设置丢弃DEBUG、TRACE、INFO日志的阀值,不丢失 -->
        <discardingThreshold>0</discardingThreshold>
        <!-- 设置队列入队时非阻塞,当队列满时会直接丢弃日志,但是对性能提升极大 -->
        <neverBlock>true</neverBlock>
    </appender>

    <!-- 将项目本次运行DEBUG日志同步输出到文件,按照每天生成日志文件,会自动拼接上一次日志 -->
    <appender name="APPENDER-ROLLINGFILEAPPENDER-DEBUG" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <!-- 过滤器,只记录 info 级别以上的日志 -->
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <level>DEBUG</level>
        </filter>
        <!--立即刷新,设置成false可以提高日志吞吐量-->
        <immediateFlush>false</immediateFlush>
        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
            <!-- 日志文件输出的文件名:
                %d:可以包含一个Java.text.SimpleDateFormat指定的时间格式
                %i:自增数字
            -->
            <fileNamePattern>${LOG_PATH}/${MACHINE_IP}/${VIRTUAL_IP}/HISTORY/${LOG_NAME}-debug-%d{yyyy-MM-dd}-index%i.log</fileNamePattern>
            <!-- 日志文件保存历史数量:控制保留的归档文件的最大数量,如果超出数量就删除旧文件 -->
            <maxHistory>10</maxHistory>
            <!-- 文件大小超过100MB归档 -->
            <maxFileSize>20MB</maxFileSize>
        </rollingPolicy>
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <pattern>${FILE_LOG_PATTERN}</pattern>
            <charset>${ENCODING}</charset>
        </encoder>
    </appender>

    <!-- 将项目本次运行DEBUG日志异步输出到文件,按照每天生成日志文件,会自动拼接上一次日志 -->
    <appender name="ASYNC-APPENDER-ROLLINGFILEAPPENDER-DEBUG" class="ch.qos.logback.classic.AsyncAppender">
        <appender-ref ref="APPENDER-ROLLINGFILEAPPENDER-DEBUG" />
        <!-- 设置异步阻塞队列的大小,为了不丢失日志建议设置的大一些,单机压测时100000是没问题的,应该不用担心OOM -->
        <queueSize>10000</queueSize>
        <!-- 设置丢弃DEBUG、TRACE、INFO日志的阀值,不丢失 -->
        <discardingThreshold>0</discardingThreshold>
        <!-- 设置队列入队时非阻塞,当队列满时会直接丢弃日志,但是对性能提升极大 -->
        <neverBlock>true</neverBlock>
    </appender>

    <!-- 将项目本次运行ERROR日志同步输出到文件,按照每天生成日志文件,会自动拼接上一次日志 -->
    <appender name="APPENDER-ROLLINGFILEAPPENDER-ERROR" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <!-- 过滤器,只记录error级别的日志 -->
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>ERROR</level>
            <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>
        <!--立即刷新,设置成false可以提高日志吞吐量-->
        <immediateFlush>false</immediateFlush>
        <!-- 每天生成一个日志文件,保存30天的日志文件 -->
        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
            <!-- 日志文件输出的文件名:按天回滚 daily -->
            <fileNamePattern>${LOG_PATH}/${MACHINE_IP}/${VIRTUAL_IP}/HISTORY/${LOG_NAME}-error-%d{yyyy-MM-dd}-index%i.log</fileNamePattern>
            <!-- 日志文件保留天数 -->
            <maxHistory>10</maxHistory>
            <!-- 文件大小超过100MB归档 -->
            <maxFileSize>20MB</maxFileSize>
        </rollingPolicy>
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <pattern>${FILE_LOG_PATTERN}</pattern>
            <charset>utf8</charset>
        </encoder>
    </appender>

    <appender name="ASYNC-APPENDER-ROLLINGFILEAPPENDER-ERROR" class="ch.qos.logback.classic.AsyncAppender">
        <appender-ref ref="APPENDER-ROLLINGFILEAPPENDER-ERROR" />
        <!-- 设置异步阻塞队列的大小,为了不丢失日志建议设置的大一些,单机压测时100000是没问题的,应该不用担心OOM -->
        <queueSize>10000</queueSize>
        <!-- 设置丢弃DEBUG、TRACE、INFO日志的阀值,不丢失 -->
        <discardingThreshold>0</discardingThreshold>
        <!-- 设置队列入队时非阻塞,当队列满时会直接丢弃日志,但是对性能提升极大 -->
        <neverBlock>true</neverBlock>
    </appender>
    <!--滚动输出到文件(按照天保存):结束-->

    <!--输出到LOGSTASH:开始-->
    <!-- 将项目本次运行ERROR日志同步输出到文件,按照每天生成日志文件,会自动拼接上一次日志 -->
    <appender name="APPENDER-LOGSTASH" class="net.logstash.logback.appender.LogstashTcpSocketAppender">
        <!--  logstash服务器地址-->
        <destination>${LOGSTASH_HOST}</destination>
        <encoder class="net.logstash.logback.encoder.LoggingEventCompositeJsonEncoder">
            <providers>
                <pattern>
                    <pattern>
                        {
                        "appName":"${INDEX_NAME}",
                        "machineIp":"${MACHINE_IP}",
                        "virtualIp":"${VIRTUAL_IP}",
                        "serviceName":"${LOG_NAME}",
                        "timestamp": "%date{\"yyyy-MM-dd'T'HH:mm:ss,SSSZ\"}",
                        "logLevel":"%level",
                        "message":"%msg%n",
                        "traceId": "%X{X-B3-TraceId:-}",
                        "spanId": "%X{X-B3-SpanId:-}",
                        "spanExport": "%X{X-Span-Export:-}"
                        }
                    </pattern>
                </pattern>
            </providers>
        </encoder>
    </appender>
    <appender name="ASYNC-APPENDER-LOGSTASH" class="ch.qos.logback.classic.AsyncAppender">
        <appender-ref ref="APPENDER-LOGSTASH" />
        <!-- 设置异步阻塞队列的大小,为了不丢失日志建议设置的大一些,单机压测时100000是没问题的,应该不用担心OOM -->
        <queueSize>10000</queueSize>
        <!-- 设置丢弃DEBUG、TRACE、INFO日志的阀值,不丢失 -->
        <discardingThreshold>0</discardingThreshold>
        <!-- 设置队列入队时非阻塞,当队列满时会直接丢弃日志,但是对性能提升极大 -->
        <neverBlock>true</neverBlock>
    </appender>
    <!--输出到logstash:结束-->

    <!--
        开发环境日志级别为DEBUG
        level:用来设置打印级别
        五个常用打印级别从低至高依次为TRACE、DEBUG、INFO、WARN、ERROR
    -->
    <springProfile name="dev">
        <root>
            <!--输出到控制台-->
            <appender-ref ref="STDOUT"/>
            <!--异步非滚动输出到文件-->
            <appender-ref ref="ASYNC-APPENDER-FILEAPPENDER-INFO"/>
            <appender-ref ref="ASYNC-APPENDER-FILEAPPENDER-DEBUG"/>
            <appender-ref ref="ASYNC-APPENDER-FILEAPPENDER-ERROR"/>
            <!--异步滚动输出到文件:dev环境不开启-->
<!--            <appender-ref ref="ASYNC-APPENDER-ROLLINGFILEAPPENDER-INFO"/>-->
<!--            <appender-ref ref="ASYNC-APPENDER-ROLLINGFILEAPPENDER-DEBUG"/>-->
<!--            <appender-ref ref="ASYNC-APPENDER-ROLLINGFILEAPPENDER-ERROR"/>-->
            <!--异步滚动输出到logstash-->
            <appender-ref ref="ASYNC-APPENDER-LOGSTASH"/>
        </root>
    </springProfile>

    <!-- 测试环境日志级别为INFO -->
    <springProfile name="test">
        <root>
            <!--输出到控制台-->
            <appender-ref ref="STDOUT"/>
            <!--异步非滚动输出到文件-->
            <appender-ref ref="ASYNC-APPENDER-FILEAPPENDER-INFO"/>
            <appender-ref ref="ASYNC-APPENDER-FILEAPPENDER-DEBUG"/>
            <appender-ref ref="ASYNC-APPENDER-FILEAPPENDER-ERROR"/>
            <!--异步滚动输出到文件:test环境不开启-->
<!--            <appender-ref ref="ASYNC-APPENDER-ROLLINGFILEAPPENDER-INFO"/>-->
<!--            <appender-ref ref="ASYNC-APPENDER-ROLLINGFILEAPPENDER-DEBUG"/>-->
<!--            <appender-ref ref="ASYNC-APPENDER-ROLLINGFILEAPPENDER-ERROR"/>-->
            <!--异步滚动输出到logstash-->
            <appender-ref ref="ASYNC-APPENDER-LOGSTASH"/>
        </root>
    </springProfile>

    <!-- 生产环境日志级别为INFO -->
    <springProfile name="prod">
        <root>
            <!--输出到控制台-->
            <appender-ref ref="STDOUT"/>
            <!--异步非滚动输出到文件-->
            <appender-ref ref="ASYNC-APPENDER-FILEAPPENDER-INFO"/>
            <appender-ref ref="ASYNC-APPENDER-FILEAPPENDER-DEBUG"/>
            <appender-ref ref="ASYNC-APPENDER-FILEAPPENDER-ERROR"/>
            <!--异步滚动输出到文件-->
            <appender-ref ref="ASYNC-APPENDER-ROLLINGFILEAPPENDER-INFO"/>
            <appender-ref ref="ASYNC-APPENDER-ROLLINGFILEAPPENDER-DEBUG"/>
            <appender-ref ref="ASYNC-APPENDER-ROLLINGFILEAPPENDER-ERROR"/>
            <!--异步滚动输出到logstash-->
            <appender-ref ref="ASYNC-APPENDER-LOGSTASH"/>
        </root>
    </springProfile>

    <!-- rancher环境日志级别为INFO -->
    <springProfile name="rancher">
        <root>
            <!--输出到控制台-->
            <appender-ref ref="STDOUT"/>
            <!--异步非滚动输出到文件-->
            <appender-ref ref="ASYNC-APPENDER-FILEAPPENDER-INFO"/>
            <appender-ref ref="ASYNC-APPENDER-FILEAPPENDER-DEBUG"/>
            <appender-ref ref="ASYNC-APPENDER-FILEAPPENDER-ERROR"/>
            <!--异步滚动输出到文件-->
            <appender-ref ref="ASYNC-APPENDER-ROLLINGFILEAPPENDER-INFO"/>
            <appender-ref ref="ASYNC-APPENDER-ROLLINGFILEAPPENDER-DEBUG"/>
            <appender-ref ref="ASYNC-APPENDER-ROLLINGFILEAPPENDER-ERROR"/>
            <!--异步滚动输出到logstash-->
            <appender-ref ref="ASYNC-APPENDER-LOGSTASH"/>
        </root>
    </springProfile>
</configuration>

20.8.6.编写模块service实现类

PaymentServiceOpenFeign.java
package org.openatom.springcloud.service;

import org.openatom.springcloud.entities.CommonResult;
import org.openatom.springcloud.entities.Payment;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;

/**
 * 使用系统自带的OpenFeignClient发起调用
 */
@Component
@FeignClient(name="SPRINGCLOUD-BASIC-SAMPLE-PROVIDER-PAYMENT-SERVICE-CLUSTER-DEV")
public interface PaymentServiceOpenFeign {
    @PostMapping(value = "/provider/payment/create")
    CommonResult create(@RequestBody Payment payment);

    @GetMapping(value = "/provider/payment/get/{id}")
    CommonResult<Payment> getPaymentById(@PathVariable("id") Long id);

    /**
     * 使用拦截器替换路由服务提供端URL中的占位符
     * @param id
     * @return
     */
    @GetMapping(value = "/provider/$evn/get/{id}")
    CommonResult<Payment> getPaymentByIdReplaceRouter(@PathVariable("id") Long id);

    @GetMapping(value = "/provider/payment/openfeign/timeout")
    String getPaymentByIdTimeout();
}

PaymentServiceOpenFeignDynamicFeignClientFactory.java
package org.openatom.springcloud.service;

import org.openatom.springcloud.entities.CommonResult;
import org.openatom.springcloud.entities.Payment;
import org.springframework.stereotype.Service;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;

/**
 * 使用自定义的自带的OpenFeignClient发起调用
 */
@Service
public interface PaymentServiceOpenFeignDynamicFeignClientFactory {
    @PostMapping(value = "/provider/payment/create")
    CommonResult create(@RequestBody Payment payment);

    @GetMapping(value = "/provider/payment/get/{id}")
    CommonResult<Payment> getPaymentById(@PathVariable("id") Long id);

    /**
     * 使用拦截器替换路由服务提供端URL中的占位符
     * @param id
     * @return
     */
    @GetMapping(value = "/provider/$evn/get/{id}")
    CommonResult<Payment> getPaymentByIdReplaceRouter(@PathVariable("id") Long id);

    @GetMapping(value = "/provider/payment/openfeign/timeout")
    String getPaymentByIdTimeout();
}

20.8.7.编写模块controller

OrderConsumerController.java
package org.openatom.springcloud.controller;

import lombok.extern.slf4j.Slf4j;
import org.openatom.springcloud.service.PaymentServiceOpenFeign;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
import org.openatom.springcloud.entities.CommonResult;
import org.openatom.springcloud.entities.Payment;

import javax.annotation.Resource;

/**
 * DEV环境测试用这个Controller,可以动态获取服务名
 */

@RestController
@Slf4j
public class OrderConsumerController {

    //单机版
//    public static final String PAYMENT_URL = "http://localhost:8001";
//    public static final String PAYMENT_URL = "http://localhost:8002";

    @Resource
    private PaymentServiceOpenFeign paymentServiceOpenFeign;

    @GetMapping("/consumer/payment/create")
    public CommonResult<Payment> create(Payment payment) {
        return paymentServiceOpenFeign.create(payment);
    }

    /**
     * 测试url:
     *      http://localhost/consumer/payment/get/1
     * @param id
     * @return
     */
    @GetMapping("/consumer/payment/get/{id}")
    public CommonResult<Payment> getPayment(@PathVariable("id") Long id) {
        return paymentServiceOpenFeign.getPaymentById(id);
    }

    /**
     * 使用拦截器替换路由服务提供端URL中的占位符
     * 测试url:
     *      http://localhost/consumer/payment/replace_router/get/1
     * @param id
     * @return
     */
    @GetMapping("/consumer/payment/replace_router/get/{id}")
    public CommonResult<Payment> getPaymentReplaceRouter(@PathVariable("id") Long id) {
        return paymentServiceOpenFeign.getPaymentByIdReplaceRouter(id);
    }

    @GetMapping("/consumer/payment/openfeign/timeout")
    public String getPaymentByIdTimeout() {
        return paymentServiceOpenFeign.getPaymentByIdTimeout();
    }
}

OrderConsumerControllerDynamicFeignClientFactory.java
package org.openatom.springcloud.controller;

import lombok.extern.slf4j.Slf4j;
import org.openatom.springcloud.entities.CommonResult;
import org.openatom.springcloud.entities.Payment;
import org.openatom.springcloud.config.DynamicFeignClientFactoryConfig;
import org.openatom.springcloud.service.PaymentServiceOpenFeignDynamicFeignClientFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;

/**
 * 多环境测试用这个Controller,可以动态获取服务名
 */
@RestController
@Slf4j
public class OrderConsumerControllerDynamicFeignClientFactory {

    //单机版
//    public static final String PAYMENT_URL = "http://localhost:8001";
//    public static final String PAYMENT_URL = "http://localhost:8002";

    //集群版
    //从配置文件中动态获取远程调用地址
    @Value("${service.provider.provider-1}")
    private String SERVICE_PROVIDER_NAME;

    @Autowired
    private DynamicFeignClientFactoryConfig<PaymentServiceOpenFeignDynamicFeignClientFactory> client;

    /**
     * 获取具体的Service接口
     * @return
     */
    public PaymentServiceOpenFeignDynamicFeignClientFactory getPaymentService() {
       return client.getFeignClient(PaymentServiceOpenFeignDynamicFeignClientFactory.class,
               SERVICE_PROVIDER_NAME.toUpperCase());
    }

    @GetMapping("/consumer/dynamic/payment/create")
    public CommonResult<Payment> create(Payment payment) {
        return this.getPaymentService().create(payment);
    }

    /**
     * 测试url:
     *      http://localhost/consumer/dynamic/payment/get/1
     * @param id
     * @return
     */
    @GetMapping("/consumer/dynamic/payment/get/{id}")
    public CommonResult<Payment> getPayment(@PathVariable("id") Long id) {
        return this.getPaymentService().getPaymentById(id);
    }

    /**
     * 使用拦截器替换路由服务提供端URL中的占位符
     * 测试url:
     *      http://localhost/consumer/dynamic/payment/replace_router/get/1
     * @param id
     * @return
     */
    @GetMapping("/consumer/dynamic/payment/replace_router/get/{id}")
    public CommonResult<Payment> getPaymentReplaceRouter(@PathVariable("id") Long id) {
        return this.getPaymentService().getPaymentByIdReplaceRouter(id);
    }

    @GetMapping("/consumer/dynamic/payment/openfeign/timeout")
    public String getPaymentByIdTimeout() {
        return this.getPaymentService().getPaymentByIdTimeout();
    }
}

20.8.8.编写模块config

VirtualIpConfig.java
package org.openatom.springcloud.config;

import ch.qos.logback.core.PropertyDefinerBase;
import lombok.extern.slf4j.Slf4j;

import java.net.InetAddress;
import java.net.UnknownHostException;

@Slf4j
public class VirtualIpConfig extends PropertyDefinerBase {
    private static String virtualIp;
    static {
        try {
            virtualIp = InetAddress.getLocalHost().getHostAddress();
        } catch (UnknownHostException e) {
            log.error("获取日志Ip异常", e);
            virtualIp = null;
        }
    }

    @Override
    public String getPropertyValue() {
        return virtualIp;
    }
}

OpenFeignConfig.java
package org.openatom.springcloud.config;

import feign.Logger;
import feign.Retryer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.concurrent.TimeUnit;

@Configuration
public class OpenFeignConfig {

    /**
     * NONE:默认的,不显示任何日志;
     * BASIC:仅记录请求方法、URL、响应状态码及执行时间;
     * HEADERS:除了BASIC中定义的信息之外,还有请求和响应的头信息;
     * FULL:除了HEADERS中定义的信息之外,还有请求和响应的正文及元数据。
     * @return
     */
    @Bean
    Logger.Level feignLoggerLevel() {
        return Logger.Level.FULL;
    }
}

DynamicFeignClientFactoryConfig.java
package org.openatom.springcloud.config;

import org.springframework.cloud.openfeign.FeignClientBuilder;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Configuration;

/**
 * 当前使用的是yml中配置的负载均衡策略
 * @param <T>
 */
@Configuration
public class DynamicFeignClientFactoryConfig<T> {

    private FeignClientBuilder feignClientBuilder;

    public DynamicFeignClientFactoryConfig(ApplicationContext appContext) {
        this.feignClientBuilder = new FeignClientBuilder(appContext);
    }

    public T getFeignClient(final Class<T> type, String serviceId) {
        return this.feignClientBuilder.forType(type, serviceId).build();
    }
}

20.8.9.编写模块interceptor

FeignClientRequestInterceptor.java
package org.openatom.springcloud.interceptor;

import feign.RequestInterceptor;
import feign.RequestTemplate;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Configuration;

/**
 * @Description Feign发起远程调用之前的请求拦截器
 *      注意:不管是系统自带的FeignClient还是用户自定义的FeignClietn执行时这个拦截器都会生效
 **/
@Slf4j
@Configuration
public class FeignClientRequestInterceptor implements RequestInterceptor {

    /**
     * @description: 将traceId设置到请求头
     */
    @Override
    public void apply(RequestTemplate template) {
        String url = template.url();
        log.info("替换前的url:" + url);
        if (url.contains("$evn")) {
            url = url.replace("$evn", replaceRouter());
            template.uri(url);
        }
        log.info("替换后的url:" + url);
    }

    /**
     * 替换router中的字符串
     * @return
     */
    private CharSequence replaceRouter() {
        return "payment";
    }
}

20.8.10.编写模块主启动类

package org.openatom.springcloud;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.cloud.openfeign.EnableFeignClients;

/**
 * 1.使用OpenFeign完成远程调用,如果要配置负载均衡策略,和Ribbon配置负载均衡策略方式相同
 *      本微服务主要测试OpenFeign的功能,所以采用YML文件配置Ribbon的负载均衡策略
 * 2.OpenFeign是对Ribbon和RestTemplate的封装,所以配置负载均衡方式同Ribbon配置负载均衡方式,而且不需要在容器中手动注入ResTemplate对象
 * 3.OpenFeign YML文件配置实现远程调用,但不是完全将服务信息配置在YML中,只是在YML中写一些增强的配置,相关的服务中仍然要写服务名,@FeignClient(name="SPRING-CLOUD-PROVIDER-CONSUL-PAYMENT-SERVICE")
 * 4.对每个微服务单独进行配置,如连接超时时间配置、读取超时时间配置,YML没有把OpenFegin的配置和对Ribbon的配置写在一起
 * 5.开启OpenFeign增强日志后可以看到Http调用的详细信息
 *      2022-06-01 03:51:37.176 DEBUG 16792 --- [p-nio-80-exec-1] o.o.s.services.PaymentServiceOpenFeign   : [PaymentServiceOpenFeign#getPaymentById] <--- HTTP/1.1 200 (59ms)
 *      2022-06-01 03:51:37.176 DEBUG 16792 --- [p-nio-80-exec-1] o.o.s.services.PaymentServiceOpenFeign   : [PaymentServiceOpenFeign#getPaymentById] connection: keep-alive
 *      2022-06-01 03:51:37.176 DEBUG 16792 --- [p-nio-80-exec-1] o.o.s.services.PaymentServiceOpenFeign   : [PaymentServiceOpenFeign#getPaymentById] content-type: application/json
 *      2022-06-01 03:51:37.176 DEBUG 16792 --- [p-nio-80-exec-1] o.o.s.services.PaymentServiceOpenFeign   : [PaymentServiceOpenFeign#getPaymentById] date: Tue, 31 May 2022 19:51:37 GMT
 *      2022-06-01 03:51:37.176 DEBUG 16792 --- [p-nio-80-exec-1] o.o.s.services.PaymentServiceOpenFeign   : [PaymentServiceOpenFeign#getPaymentById] keep-alive: timeout=60
 *      2022-06-01 03:51:37.176 DEBUG 16792 --- [p-nio-80-exec-1] o.o.s.services.PaymentServiceOpenFeign   : [PaymentServiceOpenFeign#getPaymentById] transfer-encoding: chunked
 *      2022-06-01 03:51:37.176 DEBUG 16792 --- [p-nio-80-exec-1] o.o.s.services.PaymentServiceOpenFeign   : [PaymentServiceOpenFeign#getPaymentById]
 *      2022-06-01 03:51:37.176 DEBUG 16792 --- [p-nio-80-exec-1] o.o.s.services.PaymentServiceOpenFeign   : [PaymentServiceOpenFeign#getPaymentById] {"code":200,"message":"查询成功,serverPort:  8006","data":{"id":1,"serial":"15646546546"}}
 *      2022-06-01 03:51:37.176 DEBUG 16792 --- [p-nio-80-exec-1] o.o.s.services.PaymentServiceOpenFeign   : [PaymentServiceOpenFeign#getPaymentById] <--- END HTTP (94-byte body)
 */
@EnableEurekaClient  //添加@EnableEurekaClient好像没什么用,但是还是加上
@SpringBootApplication
@EnableFeignClients
public class BasicSampleOrderServiceConsumerLoadBalanceOpenFeignConfiguration80 {
    public static void main(String[] args) {
        SpringApplication.run(BasicSampleOrderServiceConsumerLoadBalanceOpenFeignConfiguration80.class, args);
    }
}

20.9.搭建SpringBootAdminServer

20.9.1.模块简介

SpringBootAdmin的Server端,启动端口: 9004

20.9.2.模块目录结构

springcloud-basic-sample-mointor-springboot-admin-server9004
|-- src
|   •-- main
|       |-- java
|       |   •-- org
|       |       •-- openatom
|       |           •-- springcloud
|       |               |-- endpoint
|       |               |   •-- CoustomEndpoint.java
|       |               •-- BasicSampleMointorSpringBootAdmin9004.java
|       •-- resources
|           |-- dev
|           |   |-- application-dev.yml
|           |   •-- application.yml
|           |-- prod
|           |   |-- application-prod.yml
|           |   |-- application.yml
|           |   •-- logback-custom.xml
|           |-- rancher
|           |   |-- application-rancher.yml
|           |   •-- application.yml
|           •-- test
|               |-- application-test.yml
|               •-- application.yml
•-- pom.xml

20.9.3.创建模块

在父工程(springcloud-eureka)中创建一个名为springcloud-basic-sample-mointor-springboot-admin-server9004的maven模块,注意:当前模块创建成功后,在父工程pom.xml中<modules></modules>中会自动生成有关当前模块的信息

20.9.4.编写模块pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>springcloud-eureka</artifactId>
        <groupId>org.openatom</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>springcloud-basic-sample-mointor-springboot-admin-server9004</artifactId>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
        <dependency>
            <groupId>org.openatom</groupId>
            <artifactId>springcloud-api-commons</artifactId>
        </dependency>
        <dependency>
            <groupId>de.codecentric</groupId>
            <artifactId>spring-boot-admin-starter-server</artifactId>
        </dependency>
    </dependencies>
    <!--热部署需要加这个-->
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <executions>
                    <execution>
                        <goals>
                            <goal>repackage</goal>
                        </goals>
                    </execution>
                </executions>
                <configuration>
                    <fork>true</fork>
                    <addResources>true</addResources>
                </configuration>
            </plugin>
        </plugins>
        <!--打包多环境-->
        <resources>
            <resource>
                <directory>src/main/resources</directory>
                <excludes>
                    <exclude>**/*.yml</exclude>
                    <exclude>**/*.xml</exclude>
                </excludes>
            </resource>
            <resource>
                <directory>src/main/resources/${profile.active}</directory>
                <!--引入所需环境的配置文件-->
                <filtering>true</filtering>
                <includes>
                    <include>application.yml</include>
                    <!--根据maven选择环境导入配置文件-->
                    <include>application-${profile.active}.yml</include>
                    <include>mapper/*.xml</include>
                    <include>*.xml</include>
                </includes>
            </resource>
        </resources>
    </build>
</project>

20.9.5.编写模块配置文件

dev环境配置文件
application.yml
#设置spring项目运行的环境
spring:
  profiles:
    active: '@profile.active@'


application-dev.yml
server:
  port: 9004 #访问端口
spring:
  application:
    name: SPRINGCLOUD-BASIC-SAMPLE-MOINTOR-SPRINGBOOT-ADMIN-SERVER-DEV  #注意:服务名不要出现_
  devtools: #热部署开关
    restart:
      enabled: true
management:
  endpoint:
    health:
      show-details: always
  endpoints:
    web:
      exposure:
        include: '*'
      enabled-by-default: true
eureka:
  client:
    register-with-eureka: true  #表示是否将自己注册进EurekaServer默认为true。
    fetchRegistry: true  #是否从EurekaServer抓取已有的注册信息,默认为true。单节点无所谓,集群必须设置为true才能配合ribbon使用负载均衡
    service-url:
      #单机版
      defaultZone: http://localhost:7005/eureka
      #集群版
      #defaultZone: http://eureka7002:7002/eureka,http://eureka7003:7003/eureka,http://eureka7004:7004/eureka
  instance:
    instance-id: SPRINGCLOUD-MOINTOR-SPRINGBOOT-ADMIN-SERVER #Eureka仪表盘中Instances currently registered with Eureka.Status显示的内容
    prefer-ip-address: true  #访问路径可以显示IP地址,点击Eureka仪表盘中Instances currently registered with Eureka.Status显示的内容地址栏是否显示IP地址
    lease-renewal-interval-in-seconds: 30 #Eureka客户端向服务端发送心跳的时间间隔,单位为秒(默认是30秒)
    lease-expiration-duration-in-seconds: 90 #Eureka服务端在收到最后一次心跳后等待时间上限,单位为秒(默认是90秒),超时将剔除服务

prod环境配置文件
application.yml
#设置spring项目运行的环境
spring:
  profiles:
    active: '@profile.active@'


application-prod.yml
server:
  port: 9004 #访问端口
spring:
  application:
    name: SPRINGCLOUD-BASIC-SAMPLE-MOINTOR-SPRINGBOOT-ADMIN-SERVER-PROD  #注意:服务名不要出现_
  devtools: #热部署开关
    restart:
      enabled: true
management:
  endpoint:
    health:
      show-details: always
  endpoints:
    web:
      exposure:
        include: '*'
      enabled-by-default: true
eureka:
  client:
    register-with-eureka: true  #表示是否将自己注册进EurekaServer默认为true。
    fetchRegistry: true  #是否从EurekaServer抓取已有的注册信息,默认为true。单节点无所谓,集群必须设置为true才能配合ribbon使用负载均衡
    service-url:
      #单机版
      defaultZone: http://localhost:7005/eureka
      #集群版
      #defaultZone: http://eureka7002:7002/eureka,http://eureka7003:7003/eureka,http://eureka7004:7004/eureka
  instance:
    instance-id: SPRINGCLOUD-MOINTOR-SPRINGBOOT-ADMIN-SERVER #Eureka仪表盘中Instances currently registered with Eureka.Status显示的内容
    prefer-ip-address: true  #访问路径可以显示IP地址,点击Eureka仪表盘中Instances currently registered with Eureka.Status显示的内容地址栏是否显示IP地址
    lease-renewal-interval-in-seconds: 30 #Eureka客户端向服务端发送心跳的时间间隔,单位为秒(默认是30秒)
    lease-expiration-duration-in-seconds: 90 #Eureka服务端在收到最后一次心跳后等待时间上限,单位为秒(默认是90秒),超时将剔除服务

rancher环境配置文件
application.yml
#设置spring项目运行的环境
spring:
  profiles:
    active: '@profile.active@'


application-rancher.yml
server:
  port: 9004 #访问端口
spring:
  application:
    name: SPRINGCLOUD-BASIC-SAMPLE-MOINTOR-SPRINGBOOT-ADMIN-SERVER-RANCHER  #注意:服务名不要出现_
  devtools: #热部署开关
    restart:
      enabled: true
management:
  endpoint:
    health:
      show-details: always
  endpoints:
    web:
      exposure:
        include: '*'
      enabled-by-default: true
eureka:
  client:
    register-with-eureka: true  #表示是否将自己注册进EurekaServer默认为true。
    fetchRegistry: true  #是否从EurekaServer抓取已有的注册信息,默认为true。单节点无所谓,集群必须设置为true才能配合ribbon使用负载均衡
    service-url:
      #单机版
      defaultZone: http://localhost:7005/eureka
      #集群版
      #defaultZone: http://eureka7002:7002/eureka,http://eureka7003:7003/eureka,http://eureka7004:7004/eureka
  instance:
    instance-id: SPRINGCLOUD-MOINTOR-SPRINGBOOT-ADMIN-SERVER #Eureka仪表盘中Instances currently registered with Eureka.Status显示的内容
    prefer-ip-address: true  #访问路径可以显示IP地址,点击Eureka仪表盘中Instances currently registered with Eureka.Status显示的内容地址栏是否显示IP地址
    lease-renewal-interval-in-seconds: 30 #Eureka客户端向服务端发送心跳的时间间隔,单位为秒(默认是30秒)
    lease-expiration-duration-in-seconds: 90 #Eureka服务端在收到最后一次心跳后等待时间上限,单位为秒(默认是90秒),超时将剔除服务

test环境配置文件
application.yml
#设置spring项目运行的环境
spring:
  profiles:
    active: '@profile.active@'


application-test.yml
server:
  port: 9004 #访问端口
spring:
  application:
    name: SPRINGCLOUD-BASIC-SAMPLE-MOINTOR-SPRINGBOOT-ADMIN-SERVER-TEST  #注意:服务名不要出现_
  devtools: #热部署开关
    restart:
      enabled: true
management:
  endpoint:
    health:
      show-details: always
  endpoints:
    web:
      exposure:
        include: '*'
      enabled-by-default: true
eureka:
  client:
    register-with-eureka: true  #表示是否将自己注册进EurekaServer默认为true。
    fetchRegistry: true  #是否从EurekaServer抓取已有的注册信息,默认为true。单节点无所谓,集群必须设置为true才能配合ribbon使用负载均衡
    service-url:
      #单机版
      defaultZone: http://localhost:7005/eureka
      #集群版
      #defaultZone: http://eureka7002:7002/eureka,http://eureka7003:7003/eureka,http://eureka7004:7004/eureka
  instance:
    instance-id: SPRINGCLOUD-MOINTOR-SPRINGBOOT-ADMIN-SERVER #Eureka仪表盘中Instances currently registered with Eureka.Status显示的内容
    prefer-ip-address: true  #访问路径可以显示IP地址,点击Eureka仪表盘中Instances currently registered with Eureka.Status显示的内容地址栏是否显示IP地址
    lease-renewal-interval-in-seconds: 30 #Eureka客户端向服务端发送心跳的时间间隔,单位为秒(默认是30秒)
    lease-expiration-duration-in-seconds: 90 #Eureka服务端在收到最后一次心跳后等待时间上限,单位为秒(默认是90秒),超时将剔除服务

20.9.6.编写模块主启动类

package org.openatom.springcloud;

import de.codecentric.boot.admin.server.config.EnableAdminServer;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@EnableAdminServer
@SpringBootApplication
public class BasicSampleMointorSpringBootAdmin9004 {

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

20.10.测试适用于生产环境的微服务

20.10.1.测试多环境相关配置

20.10.1.1.测试多环境运行

dev环境
在浏览器访问
http://localhost:7005/
可以看到服务名为SPRINGCLOUD-BASIC-SAMPLE-REGISTER-CENTER-SINGLE-NODE7005-DEV

test环境
在浏览器访问
http://localhost:7005/

20.10.1.2.测试多环境打包

dev环境
执行如下命令
jar xf springcloud-basic-sample-register-center-single-node7005.jar &&
ls BOOT-INF/classes/
查看jar包中使用的配置文件
application.yml  application-dev.yml  logback-custom.xml  org
只包含了application-dev.yml这个多环境配置文件,其他的多环境配置配置都没有被包含进来

test环境
执行如下命令
jar xf springcloud-basic-sample-register-center-single-node7005.jar &&
ls BOOT-INF/classes/
查看jar包中使用的配置文件
application.yml  application-test.yml  logback-custom.xml  org
只包含了application-test.yml这个多环境配置文件,其他的多环境配置配置都没有被包含进来

20.10.2.测试微服务监控技术

启动相关服务
在浏览器访问
http://localhost:7005/
可以看到SpringbootAdminServer中已经监控到了相关的服务,可以点击具体服务查看详细信息,这里不在继续做展示

20.10.3.测试更完善的日志系统

20.10.3.1.测试输出日志到控制台

在idea中启动项目时可以在控制台看到输出的日志,这个输出的日志的格式自定义的,不是使用的默认的格式,详细的日志格式查看logback-custom.xml,不同的环境输出的日志格式不一定相同,具体要看logback-custom.xml中针对具体的环境设置的格式

20.10.3.2.测试输出日志到文件

在当前项目根目录执行命令
ls -R log
log:
localhost  tree.md

log/localhost:
192.168.0.1

log/localhost/192.168.0.1:
HISTORY
SPRINGCLOUD-BASIC-SAMPLE-CONSUMER-LOADBALANCE-OPENFEIGN-DYNAMIC-SERVICENAME-ORDER80-DEV-debug.log
SPRINGCLOUD-BASIC-SAMPLE-CONSUMER-LOADBALANCE-OPENFEIGN-DYNAMIC-SERVICENAME-ORDER80-DEV-error.log
SPRINGCLOUD-BASIC-SAMPLE-CONSUMER-LOADBALANCE-OPENFEIGN-DYNAMIC-SERVICENAME-ORDER80-DEV-info.log
SPRINGCLOUD-BASIC-SAMPLE-CONSUMER-LOADBALANCE-OPENFEIGN-DYNAMIC-SERVICENAME-ORDER80-TEST-debug.log
SPRINGCLOUD-BASIC-SAMPLE-CONSUMER-LOADBALANCE-OPENFEIGN-DYNAMIC-SERVICENAME-ORDER80-TEST-error.log
SPRINGCLOUD-BASIC-SAMPLE-CONSUMER-LOADBALANCE-OPENFEIGN-DYNAMIC-SERVICENAME-ORDER80-TEST-info.log
SPRINGCLOUD-BASIC-SAMPLE-PROVIDER-PAYMENT-SERVICE-CLUSTER-DEV-debug.log
SPRINGCLOUD-BASIC-SAMPLE-PROVIDER-PAYMENT-SERVICE-CLUSTER-DEV-error.log
SPRINGCLOUD-BASIC-SAMPLE-PROVIDER-PAYMENT-SERVICE-CLUSTER-DEV-info.log
SPRINGCLOUD-BASIC-SAMPLE-PROVIDER-PAYMENT-SERVICE-CLUSTER-TEST-debug.log
SPRINGCLOUD-BASIC-SAMPLE-PROVIDER-PAYMENT-SERVICE-CLUSTER-TEST-error.log
SPRINGCLOUD-BASIC-SAMPLE-PROVIDER-PAYMENT-SERVICE-CLUSTER-TEST-info.log
SPRINGCLOUD-BASIC-SAMPLE-REGISTER-CENTER-SINGLE-NODE7005-DEV-debug.log
SPRINGCLOUD-BASIC-SAMPLE-REGISTER-CENTER-SINGLE-NODE7005-DEV-error.log
SPRINGCLOUD-BASIC-SAMPLE-REGISTER-CENTER-SINGLE-NODE7005-DEV-info.log
SPRINGCLOUD-BASIC-SAMPLE-REGISTER-CENTER-SINGLE-NODE7005-TEST-debug.log
SPRINGCLOUD-BASIC-SAMPLE-REGISTER-CENTER-SINGLE-NODE7005-TEST-error.log
SPRINGCLOUD-BASIC-SAMPLE-REGISTER-CENTER-SINGLE-NODE7005-TEST-info.log

log/localhost/192.168.0.1/HISTORY:
SPRINGCLOUD-BASIC-SAMPLE-CONSUMER-LOADBALANCE-OPENFEIGN-DYNAMIC-SERVICENAME-ORDER80-DEV-debug-2022-08-30-index0.log
SPRINGCLOUD-BASIC-SAMPLE-CONSUMER-LOADBALANCE-OPENFEIGN-DYNAMIC-SERVICENAME-ORDER80-DEV-error-2022-08-30-index0.log
SPRINGCLOUD-BASIC-SAMPLE-CONSUMER-LOADBALANCE-OPENFEIGN-DYNAMIC-SERVICENAME-ORDER80-DEV-info-2022-08-30-index0.log
SPRINGCLOUD-BASIC-SAMPLE-CONSUMER-LOADBALANCE-OPENFEIGN-DYNAMIC-SERVICENAME-ORDER80-TEST-debug-2022-07-17-index0.log
SPRINGCLOUD-BASIC-SAMPLE-CONSUMER-LOADBALANCE-OPENFEIGN-DYNAMIC-SERVICENAME-ORDER80-TEST-error-2022-07-17-index0.log
SPRINGCLOUD-BASIC-SAMPLE-CONSUMER-LOADBALANCE-OPENFEIGN-DYNAMIC-SERVICENAME-ORDER80-TEST-info-2022-07-17-index0.log
SPRINGCLOUD-BASIC-SAMPLE-PROVIDER-PAYMENT-SERVICE-CLUSTER-DEV-debug-2022-08-30-index0.log
SPRINGCLOUD-BASIC-SAMPLE-PROVIDER-PAYMENT-SERVICE-CLUSTER-DEV-error-2022-08-30-index0.log
SPRINGCLOUD-BASIC-SAMPLE-PROVIDER-PAYMENT-SERVICE-CLUSTER-DEV-info-2022-08-30-index0.log
SPRINGCLOUD-BASIC-SAMPLE-PROVIDER-PAYMENT-SERVICE-CLUSTER-TEST-debug-2022-07-17-index0.log
SPRINGCLOUD-BASIC-SAMPLE-PROVIDER-PAYMENT-SERVICE-CLUSTER-TEST-error-2022-07-17-index0.log
SPRINGCLOUD-BASIC-SAMPLE-PROVIDER-PAYMENT-SERVICE-CLUSTER-TEST-info-2022-07-17-index0.log
SPRINGCLOUD-BASIC-SAMPLE-REGISTER-CENTER-SINGLE-NODE7005-DEV-debug-2022-08-30-index0.log
SPRINGCLOUD-BASIC-SAMPLE-REGISTER-CENTER-SINGLE-NODE7005-DEV-error-2022-08-30-index0.log
SPRINGCLOUD-BASIC-SAMPLE-REGISTER-CENTER-SINGLE-NODE7005-DEV-info-2022-08-30-index0.log
SPRINGCLOUD-BASIC-SAMPLE-REGISTER-CENTER-SINGLE-NODE7005-TEST-debug-2022-07-17-index0.log
SPRINGCLOUD-BASIC-SAMPLE-REGISTER-CENTER-SINGLE-NODE7005-TEST-debug-2022-08-30-index0.log
SPRINGCLOUD-BASIC-SAMPLE-REGISTER-CENTER-SINGLE-NODE7005-TEST-error-2022-07-17-index0.log
SPRINGCLOUD-BASIC-SAMPLE-REGISTER-CENTER-SINGLE-NODE7005-TEST-error-2022-08-30-index0.log
SPRINGCLOUD-BASIC-SAMPLE-REGISTER-CENTER-SINGLE-NODE7005-TEST-info-2022-07-17-index0.log
SPRINGCLOUD-BASIC-SAMPLE-REGISTER-CENTER-SINGLE-NODE7005-TEST-info-2022-08-30-index0.log

查询出来的都是输出的文件的日志,输出日志到文件时和输出日志到控制台是一样的,不同的环境输出的日志格式不一定相同,具体要看logback-custom.xml中针对具体的环境设置的格式

20.10.3.2.测试推送日志到ELK中

在192.168.0.5上搭建ELK

详细参考-> docker中安装ELK

上次编辑于: 2022/9/9 06:18:47
贡献者: lingwh
评论