原文地址:Logback 整合 RabbitMQ 实现统一日志输出 博客地址:http://www.extlight.comjava
公司项目作了集群实现请求分流,因为线上或多或少会出现请求失败或系统异常,为了查看失败请求的日志信息,咱们得将全部服务的日志文件都打开来进行问题的定位分析,操做起来很是麻烦。所以,咱们开发组决定设计一套日志查看系统来解决上述问题。spring
默认的,应用服务日志信息会保存在本地服务器的目录中,为了方便查看日志咱们应该把多台服务器日志统一输出到一个日志文件中。服务器
因为项目使用的 Logback 日志框架和 RabbitMQ 消息队列,这二者正好能够进行整合。app
所以,咱们能够将项目代码中的日志输出到 RabbitMQ 队列中,经过 Logstash 读取队列数据,最后再输出到一个日志文件中。框架
测试环境:IP 为 192.168.2.13 的 CentOS 7 系统spring-boot
首先须要搭建 RabbitMQ 环境,能够参考本站《CentOS 7.2 安装 RabbitMQ》进行搭建。测试
搭建完成后,登陆 RabbitMQ 的管理界面,须要操做以下步骤:this
操做演示图:编码
本站也有 Logstash 相关的博文,读者可移至 《Logstash 基础入门》 查看。spa
input { rabbitmq { type =>"all" durable => true exchange => "rabbit.log" exchange_type => "direct" key => "info" host => "192.168.2.13" port => 5672 user => "light" password => "light" queue => "log_queue" auto_delete => false } } output { file { path => "/usr/test-log/test-%{+YYYY-MM-dd}.log" codec => multiline { pattern => "^\d" negate => true what => "previous" } } }
注意: multiline 是 Logstash 的插件,须要手动安装。
配置表示 Logstash 服务从 RabbitMQ 读取日志信息,输出到指定的目录文件中。
列出主要依赖:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-amqp</artifactId> </dependency> <dependency> <groupId>org.springframework.amqp</groupId> <artifactId>spring-rabbit</artifactId> </dependency>
名为 logback-spring.xml
<?xml version="1.0" encoding="UTF-8"?> <configuration debug="false"> <!--定义日志文件的存储地址 勿在 LogBack 的配置中使用相对路径--> <property name="LOG_HOME" value="d:/" /> <!-- 控制台输出 --> <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"> <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder"> <!--格式化输出,%d:日期;%thread:线程名;%-5level:级别,从左显示5个字符宽度;%msg:日志消息;%n:换行符--> <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern> </encoder> </appender> <appender name="RABBITMQ" class="org.springframework.amqp.rabbit.logback.AmqpAppender"> <layout> <pattern><![CDATA[ %d %p %t [%c] - <%m>%n ]]></pattern> </layout> <!--rabbitmq地址 --> <addresses>192.168.2.13:5672</addresses> <username>light</username> <password>light</password> <declareExchange>true</declareExchange> <exchangeType>direct</exchangeType> <exchangeName>rabbit.log</exchangeName> <routingKeyPattern>info</routingKeyPattern> <generateId>true</generateId> <charset>UTF-8</charset> <durable>true</durable> <deliveryMode>NON_PERSISTENT</deliveryMode> <autoDelete>false</autoDelete> </appender> <logger name="com.light.rabbitmq" level="info" additivity="false"> <appender-ref ref="STDOUT"/> <appender-ref ref="RABBITMQ"/> </logger> <!-- 日志输出级别,level 默认值 DEBUG,root 实际上是 logger,它是 logger 的根 --> <root level="INFO"> <appender-ref ref="STDOUT" /> <appender-ref ref="RABBITMQ" /> </root> </configuration>
配置中的 exchangeType 和 exchangeName 就是咱们上边建立的交换机的类型和名称。
自定义异常:
public class CustomException extends RuntimeException{ private static final long serialVersionUID = 1L; private int code; private String msg; public CustomException(int code, String msg) { super(msg); this.code = code; this.msg = msg; } public int getCode() { return code; } public void setCode(int code) { this.code = code; } public String getMsg() { return msg; } public void setMsg(String msg) { this.msg = msg; } }
模拟打印日志:
@Component public class DemoTask { private static Logger logger = LoggerFactory.getLogger(DemoTask.class); private int num = 1; @Scheduled(fixedRate = 3000) public void writeLog() { try { if (num % 5 == 0) { throw new CustomException(500, "自定义异常错误"); } logger.info("==={}===={}","hello rabbitmq", System.currentTimeMillis()); num++; } catch (CustomException e) { e.printStackTrace(); logger.error("=={}==", e); } } }
执行启动类:
@EnableScheduling @SpringBootApplication public class RabbitmqTestApplication { public static void main(String[] args) { SpringApplication.run(RabbitmqTestApplication.class, args); } }
执行结果以下图:
代码运行的日志信息已经输出到指定日志文件中了。
补充
因为多台服务器的日志都打印到同一个文件,为了区分日志来源,咱们还得须要打印出日志信息对应的主机 ip 地址。具体实现步骤以下:
须要继承 ClassicConverter 类
public class CustomLogConverter extends ClassicConverter { public String convert(ILoggingEvent event) { try { return InetAddress.getLocalHost().getHostAddress(); } catch (UnknownHostException e) { e.printStackTrace(); } return null; } }
如下只张贴关键配置信息
<conversionRule conversionWord="ip" converterClass="com.light.rabbitmq.log.CustomLogConverter" /> <appender name="RABBITMQ" class="org.springframework.amqp.rabbit.logback.AmqpAppender"> <layout> <pattern><![CDATA[%ip %date{yyyy-MM-dd HH:mm:ss} | %highlight(%-5level) | %yellow(%thread) | %green(%logger) | %msg%n ]]></pattern> </layout> </appender>