Logback 整合 RabbitMQ 实现统一日志输出
一、前言
? ? 公司項目做了集群實現(xiàn)請求分流,由于線上或多或少會出現(xiàn)請求失敗或系統(tǒng)異常,為了查看失敗請求的日志信息,我們得將所有服務(wù)的日志文件都打開來進行問題的定位分析,操作起來非常麻煩。因此,我們開發(fā)組決定設(shè)計一套日志查看系統(tǒng)來解決上述問題。
二、實現(xiàn)思路
? ? 默認的,應(yīng)用服務(wù)日志信息會保存在本地服務(wù)器的目錄中,為了方便查看日志我們應(yīng)該把多臺服務(wù)器日志統(tǒng)一輸出到一個日志文件中。
? ? 由于項目使用的 Logback 日志框架和 RabbitMQ 消息隊列,這兩者正好可以進行整合。
? ? 因此,我們可以將項目代碼中的日志輸出到 RabbitMQ 隊列中,通過 Logstash 讀取隊列數(shù)據(jù),最后再輸出到一個日志文件中。
三、準備環(huán)境
測試環(huán)境:IP 為 192.168.2.13 的 CentOS 7 系統(tǒng)
#?3.1 RabbitMQ 配置
? ? 首先需要搭建 RabbitMQ 環(huán)境,可以參考本站《CentOS 7.2 安裝 RabbitMQ》進行搭建。
? ? 搭建完成后,登錄 RabbitMQ 的管理界面,需要操作如下步驟:
- 創(chuàng)建一個名為 log_queue 的隊列
- 創(chuàng)建一個名為 rabbit.log 的交換器(direct 類型)
- 將 log_queue 隊列綁定到 rabbit.log 交換機上
操作演示圖:
#?3.2 Logstash 配置文件
? ? 本站也有 Logstash 相關(guān)的博文,讀者可移至?《Logstash 基礎(chǔ)入門》?查看。
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" }}output {file { path => "/usr/test-log/test-%{+YYYY-MM-dd}.log" codec => multiline { pattern => "^\d" negate => true what => "previous" }} }注意: multiline 是 Logstash 的插件,需要手動安裝。
配置表示 Logstash 服務(wù)從 RabbitMQ 讀取日志信息,輸出到指定的目錄文件中。
四、編碼
#?4.1 依賴
列出主要依賴:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-amqp</artifactId> </dependency><dependency> <groupId>org.springframework.amqp</groupId> <artifactId>spring-rabbit</artifactId> </dependency>#?4.2 application.properties 文件
spring.rabbitmq.host=192.168.2.13 spring.rabbitmq.port=5672 spring.rabbitmq.username=light spring.rabbitmq.password=light#?4.3 日志文件
名為 logback-spring.xml
<?xml version="1.0" encoding="UTF-8"?> <configuration debug="false"><!--定義日志文件的存儲地址 勿在 LogBack 的配置中使用相對路徑--> <property name="LOG_HOME" value="d:/" /><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 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地址 --> <host>${rabbitmqHost}</host> <port>${rabbitmqPort}</port> <username>${rabbitmqUsername}</username> <password>${rabbitmqPassword}</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 就是我們上邊創(chuàng)建的交換機的類型和名稱。
#?4.4 測試類
自定義異常:
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); }} }五、代碼測試
執(zhí)行啟動類:
@EnableScheduling @SpringBootApplication public class RabbitmqTestApplication {public static void main(String[] args) { SpringApplication.run(RabbitmqTestApplication.class, args); }}執(zhí)行結(jié)果如下圖:
代碼運行的日志信息已經(jīng)輸出到指定日志文件中了。
補充
由于多臺服務(wù)器的日志都打印到同一個文件,為了區(qū)分日志來源,我們還得需要打印出日志信息對應(yīng)的主機 ip 地址。具體實現(xiàn)步驟如下:
- 自定義日志轉(zhuǎn)換器
需要繼承 ClassicConverter 類
public class CustomLogConverter extends ClassicConverter {public String convert(ILoggingEvent event) {try { return InetAddress.getLocalHost().getHostAddress(); } catch (UnknownHostException e) { e.printStackTrace(); } return null; } }- 修改 logback-spring.xml 文件
以下只張貼關(guān)鍵配置信息
<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>?
總結(jié)
以上是生活随笔為你收集整理的Logback 整合 RabbitMQ 实现统一日志输出的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 贪心算法之——喷水装置二(nyoj12)
- 下一篇: 动态规划之——拦截导弹(nyoj79)