原文地址: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>