springboot logback如何从apollo配置中心读取变量
作者:LMD菜鸟先飞
springboot logback 从apollo配置中心读取变量
1、在apollo配置中心添加
logback-config.properties配置文件
2、项目的application.yml配置文件配置如下
主要是eagerLoad.enabled: true这个配置
app: id: SX-sale-app-soa apollo: bootstrap: enabled: true #将Apollo配置加载提到初始化日志系统之前 eagerLoad: enabled: true namespaces: application.yml,logback-config
3、在logback.xml配置springProperty标签
设置好标签名称和配置中心变量名称的,使用的时候${name}引入该变量
<?xml version="1.0" encoding="UTF-8"?> <!-- 日志级别从低到高分为TRACE < DEBUG < INFO < WARN < ERROR < FATAL,如果设置为WARN,则低于WARN的信息都不会输出 --> <!-- scan:当此属性设置为true时,配置文件如果发生改变,将会被重新加载,默认值为true --> <!-- scanPeriod:设置监测配置文件是否有修改的时间间隔,如果没有给出时间单位,默认单位是毫秒。当scan为true时,此属性生效。默认的时间间隔为1分钟。 --> <!-- debug:当此属性设置为true时,将打印出logback内部日志信息,实时查看logback运行状态。默认值为false。 --> <configuration scan="true" scanPeriod="10 seconds"> <!-- 读取apollo配置中心设置的变量 --> <springProperty scope="context" name="logstash.host" source="logstash.host"></springProperty> <springProperty scope="context" name="logstash.port" source="logstash.port"></springProperty> <springProperty scope="context" name="log.path" source="log.path"></springProperty> <appender name="LOGSTASH" class="net.logstash.logback.appender.LogstashTcpSocketAppender"> <remoteHost>${logstash.host}</remoteHost> <port>${logstash.port}</port> <!-- encoder必须配置,有多种可选 --> <encoder charset="UTF-8" class="net.logstash.logback.encoder.LogstashEncoder" > <!-- "appname":"yang_test" 的作用是指定创建索引的名字时用,并且在生成的文档中会多了这个字段 --> <customFields>{"appname":"server-user"}</customFields> </encoder> </appender>
这个是后启动日志中会报如下错误:
20:26:50,683 |-ERROR in ch.qos.logback.core.joran.spi.Interpreter@120:31 - no applicable action for [springProfile], current ElementPath is [[configuration][springProfile]]
20:26:50,683 |-ERROR in ch.qos.logback.core.joran.spi.Interpreter@121:58 - no applicable action for [logger], current ElementPath is [[configuration][springProfile][logger]]
20:26:50,683 |-ERROR in ch.qos.logback.core.joran.spi.Interpreter@132:42 - no applicable action for [appender-ref], current ElementPath is [[configuration][springProfile][logger][appender-ref]]
这是因为日志文件的名称是logback.xml的话,logback会在SpringCloud和apollo配置加载之前加载日志配置,这时日志文件中的springProfile的配置是无效的。所以根据官方文档说明,需要将logback.xml改为logback-spring.xml,然后报错就没有了。
注:虽然logback.xml文件名启动时会报错,但是不影响实际效果,猜测是因为上边第二步中的配置会在后边再次加载logback日志,所以logback依然会产生效果,但是对于有代码洁癖的人来说,没有任何报错和异常才是最舒服的。
SpringBoot Logback无法获取配置中心属性
最近在做项目中,需要把项目中的日志信息通过RabbitMQ将规定格式的消息发送到消息队列中,然后ELK系统通过消息队列拿日志并且保存起来,在日志的配置文件(logback-spring.xml)中我们需要加入RabbitMQ的配置信息,我们的RabbitMQ信息存在Nacos的配置中心,就出现项目启动无法获取到RabbitMQ的配置,导致出错
如何解决
问题原因
在springboot官网 https://docs.spring.io/spring-boot/docs/2.0.4.RELEASE/reference/htmlsingle/
中对LogBack的描述中我们可以知道,项目启动时,logback.xml或者logback-spring.xml加载早于applicaton.yml,所以我们在logback.xml中配置的RabbitMQ属性无法获取到
<property name="rabbitmq_host" source="spring.rabbitmq.host"/> <property name="rabbitmq_vhost" source="spring.rabbitmq.virtual-host"/> <property name="rabbitmq_username" source="spring.rabbitmq.username"/> <property name="rabbitmq_password" source="spring.rabbitmq.password"/>
source指定的是application.yml配置文件的key
解决方案
将logback.xml或者logback-spring.xml文件自定义名称,并在配置中心中指定该文件,这样SpringBoot就不会在获取配置中心配置之前加载日志配置了
配置中心的配置
#RabbitMQ配置 spring: rabbitmq: host: 127.0.0.1 virtual-host: test username: admin password: 123 logging: config: classpath:logback-test.xml
日志配置
logback-test.xml
<?xml version="1.0" encoding="UTF-8"?> <configuration scan="true" scanPeriod="60 seconds" debug="false"> <!-- 日志存放路径 --> <property name="log.path" value="./target/logs/system-service" /> <!-- 参数 --> <property name="app_name" source="spring.application.name"/> <property name="app_instance_id" source="rabbitmq.instance"/> <property name="rabbitmq_host" source="spring.rabbitmq.host"/> <property name="rabbitmq_vhost" source="spring.rabbitmq.virtual-host"/> <property name="rabbitmq_username" source="spring.rabbitmq.username"/> <property name="rabbitmq_password" source="spring.rabbitmq.password"/> <!-- 日志输出格式 --> <property name="log.pattern" value="%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - [%method,%line] - %msg%n" />:ss} %-5level ${springAppName:-} %thread %logger %msg%n"/> <!-- 控制台输出 --> <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender"> <encoder> <pattern>${log.pattern}</pattern> <charset>UTF-8</charset> </encoder> </appender> <!-- 系统日志输出 --> <appender name="FIFE" class="ch.qos.logback.core.rolling.RollingFileAppender"> <file>${log.path}/${app_name}.log</file> <!-- 循环政策:基于时间创建日志文件 --> <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> <!-- 日志文件名格式 --> <fileNamePattern>${log.path}/${app_name}.%d{yyyy-MM-dd}.%i.log</fileNamePattern> <!-- 日志最大的历史 60天 --> <maxHistory>10</maxHistory> <maxFileSize>10MB</maxFileSize> </rollingPolicy> <append>true</append> <encoder> <pattern>${log.pattern}</pattern> <charset>UTF-8</charset> </encoder> <filter class="ch.qos.logback.classic.filter.LevelFilter"> <!-- 过滤的级别 --> <level>INFO</level> <!-- 匹配时的操作:接收(记录) --> <onMatch>ACCEPT</onMatch> <!-- 不匹配时的操作:拒绝(不记录) --> <onMismatch>DENY</onMismatch> </filter> </appender> <!-- 日志发送到消息队列RabbitMQ,接入ELK --> <appender name="RabbitMQ" class="org.springframework.amqp.rabbit.logback.AmqpAppender"> <!-- 纯文本,不是格式化的JSON --> <layout> <pattern> { "appName":"${app_name}", "appInstance":"${app_instance_id}", "date":"%d{yyyy-MM-dd HH:mm:ss.SSS}", "thread":"[%thread]", "level":"%-5level", "logger":"%logger{36}", "msg":"%msg" } </pattern> </layout> <host>${rabbitmq_host}</host> <port>5672</port> <username>${rabbitmq_username}</username> <password>${rabbitmq_password}</password> <virtualHost>${rabbitmq_vhost}</virtualHost> <declareExchange>false</declareExchange> <exchangeType>direct</exchangeType> <exchangeName>logs.direct</exchangeName> <routingKeyPattern>logback</routingKeyPattern> <generateId>true</generateId> <durable>false</durable> <charset>UTF-8</charset> <deliveryModel>NON_PERSISTENT</deliveryModel> <filter class="ch.qos.logback.classic.filter.LevelFilter"> <level>info</level> <onMatch>ACCEPT</onMatch> <onMismatch>DENY</onMismatch> </filter> </appender> <!--系统操作日志--> <root level="INFO"> <appender-ref ref="CONSOLE" /> <appender-ref ref="FILE" /> <appender-ref ref="RabbitMQ" /> </root> </configuration>
以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。