最近在接口项目开始使用微服务设计构架,使用的是现在流行的spring cloud技术栈。
网关做权限,限流,日志记录等前置统一入口。在网关统一记录请求及相应日志,单实例的时候情况下,没有问题,但是想到网关压力比较大,于是决定启动多个实例。但是为了查询日志方便,多实例记录的日志打算不分开,还是记录到同一个文件中(按天分割),看到这里可能有人会问,分布式日志收集,为什么不用ELK呢?我们是有ELK系统的,但是平时感觉用的还是比较少,每个日志文件每天就100M以内,而且在无服务器查询日志也挺方便的。
说说碰到的问题,当多个网关实例共同操作同一个日志文件的时候,奇怪的时候会出现只能有一个实例获取操作权限,导致其他实例的日志文件漏打(但是重启其他实例后就没问题,一天时间过后,就出现了只能记录其中一个实例的,现在还不清楚是什么问题),于是就想要不直接把的logback的日志信息,直接输出到的RabbitMQ中,然后MQ消费消息再输出到文件或者上课。大概的意思是
网关实例1日志输出----> RabbitMq |
网关实例2日志输出----> RabbitMq | ------>文件/ ES
网关实例3日志输出----> RabbitMq |
这样就不会有多个实例操作同一个日志文件的情况了,只要保证消费MQ消息正确,应该不会出现漏打日志的情况。
首先
1.配置一下RabbitMQ的需要的队里,交换器,绑定。(启动注入豆操作)
@Bean
public Queue logDirectQueue() {
return new Queue("logDirectQueue");
}
@Bean
public DirectExchange logDirectExchange() {
return new DirectExchange("log.exchange.direct", false, false);
}
/**
* 根据路由键绑定队列到交换器上
*
* @return
*/
@Bean
public Binding logDirectBinding() {
return BindingBuilder.bind(logDirectQueue()).to(logDirectExchange()).with("logDirectQueue");
}
2.Spring boot的配置文件
spring:
rabbitmq:
host: 127.0.0.1
username: guest
password: guest
port: 5672
log:
path: D:/logs/rabbitmq
logging:
config: classpath:logback-spring.xml
3.spring-logback.xml
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<!--日志存储位置(读取配置文件的路径)-->
<springProperty scope="context" name="log_dir" source="log.path"/>
<springProperty name="rabbitmqHost" source="spring.rabbitmq.host"/>
<springProperty name="rabbitmqPort" source="spring.rabbitmq.port"/>
<springProperty name="rabbitmqUsername" source="spring.rabbitmq.username"/>
<springProperty name="rabbitmqPassword" source="spring.rabbitmq.password"/>
<!-- 控制台日志 -->
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%red(%d{yyyy-MM-dd HH:mm:ss}) %green([%thread]) [%class:%line] %highlight(%-5level) - %cyan(%msg%n)
</pattern>
<charset>UTF-8</charset>
</encoder>
</appender>
<appender name="AMQP" class="org.springframework.amqp.rabbit.logback.AmqpAppender">
<!--Layout(纯文本)而不是格式化的JSON -->
<layout>
<pattern>
<![CDATA[%d{yyyy-MM-dd HH:mm:ss} [%thread] [%class:%line] %-5level %logger - %msg%n ]]>
</pattern>
</layout>
<host>${rabbitmqHost}</host>
<port>${rabbitmqPort}</port>
<username>${rabbitmqUsername}</username>
<password>${rabbitmqPassword}</password>
<declareExchange>false</declareExchange>
<exchangeType>direct</exchangeType>
<exchangeName>log.exchange.direct</exchangeName>
<routingKeyPattern>logDirectQueue</routingKeyPattern>
<generateId>true</generateId>
<charset>UTF-8</charset>
<durable>false</durable>
<deliveryMode>NON_PERSISTENT</deliveryMode>
</appender>
<!-- 文件记录只记录指定包的日志 -->
<logger name="com.example.springbootrabbitmq" level="info" additivity="false">
<appender-ref ref="STDOUT"/>
<appender-ref ref="AMQP"/>
</logger>
<root level="INFO">
<appender-ref ref="STDOUT"/>
</root>
</configuration>
这里主要是使用spring为我们提供的组织工具。
4.创建一个消费者
@Component
public class DirectConsumer {
@RabbitListener(queues = {"directQueue", "logDirectQueue"})
public void processMessage(String msg) {
System.err.println("consumer receive a message:" + msg);
}
}