Logback 整合 RabbitMQ 实现统一日志输出
原文地址:Logback 整合 RabbitMQ 实现统一日志输出
博客地址:http://www.extlight.com
一、前言
公司项目做了集群实现请求分流,由于线上或多或少会出现请求失败或系统异常,为了查看失败请求的日志信息,我们得将所有服务的日志文件都打开来进行问题的定位分析,操作起来非常麻烦。因此,我们开发组决定设计一套日志查看系统来解决上述问题。
二、实现思路
默认的,应用服务日志信息会保存在本地服务器的目录中,为了方便查看日志我们应该把多台服务器日志统一输出到一个日志文件中。
由于项目使用的 Logback 日志框架和 RabbitMQ 消息队列,这两者正好可以进行整合。
因此,我们可以将项目代码中的日志输出到 RabbitMQ 队列中,通过 Logstash 读取队列数据,最后再输出到一个日志文件中。
三、准备环境
测试环境:IP 为 192.168.2.13 的 CentOS 7 系统
3.1 RabbitMQ 配置
首先需要搭建 RabbitMQ 环境,可以参考本站《CentOS 7.2 安装 RabbitMQ》进行搭建。
搭建完成后,登录 RabbitMQ 的管理界面,需要操作如下步骤:
- 创建一个名为 log_queue 的队列
- 创建一个名为 rabbit.log 的交换器(direct 类型)
- 将 log_queue 队列绑定到 rabbit.log 交换机上
操作演示图:
3.2 Logstash 配置文件
本站也有 Logstash 相关的博文,读者可移至 《Logstash 基础入门》 查看。
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 读取日志信息,输出到指定的目录文件中。
四、编码
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 日志文件
名为 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 就是我们上边创建的交换机的类型和名称。
4.3 测试类
自定义异常:
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;
}
}
- 修改 logback-spring.xml 文件
以下只张贴关键配置信息
<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>
Logback 整合 RabbitMQ 实现统一日志输出的更多相关文章
- Spring AOP实现统一日志输出
目的: 统一日志输出格式 思路: 1.针对不同的调用场景定义不同的注解,目前想的是接口层和服务层. 2.我设想的接口层和服务层的区别在于: (1)接口层可以打印客户端IP,而服务层不需要 (2)接口层 ...
- 2.logback+slf4j+janino 配置项目的日志输出
作者QQ:1095737364 QQ群:123300273 欢迎加入! 1.创建项目 参考:http://www.cnblogs.com/yysbolg/p/6898453.html 2 ...
- springboot 学习之路 4(日志输出)
目录:[持续更新.....] spring 部分常用注解 spring boot 学习之路1(简单入门) spring boot 学习之路2(注解介绍) spring boot 学习之路3( 集成my ...
- Hibernate日志输出到SLF4J
一,Hibernate日志问题 工程使用SLF4J,但日志文件一直没有看到Hibernate相关日志及showsql 二,Logback文件配置 修改Hibernate 日志输出指定为SLF4J,当修 ...
- springboot(二).springboot整合logback用于日志输出
springboot整合logback用于日志输出 我们项目的基本框架已经完成,http请求已经可以访问,现在给我们的框架添加日志记录的功能并能将每天的记录记录到文件中去 在这里,我们使用logbac ...
- SpringBoot系列(十三)统一日志处理,logback+slf4j AOP+自定义注解,走起!
往期精彩推荐 SpringBoot系列(一)idea新建Springboot项目 SpringBoot系列(二)入门知识 springBoot系列(三)配置文件详解 SpringBoot系列(四)we ...
- springboot+logback日志输出企业实践(上)
目录 1.引言 2.logback简介 3. springboot默认日志框架-logback 3.1 springboot示例工程搭建 3.2 日志输出与基本配置 3.2.1 日志默认输出 3.2. ...
- 使用logback.xml配置来实现日志文件输出
转自:http://sungang-1120.iteye.com/blog/2104296 Logback是由log4j创始人设计的又一个开源日志组件.logback当前分成三个模块:logback- ...
- logback KafkaAppender 写入Kafka队列,集中日志输出.
为了减少应用服务器对磁盘的读写,以及可以集中日志在一台机器上,方便使用ELK收集日志信息,所以考虑做一个jar包,让应用集中输出日志 网上搜了一圈,只发现有人写了个程序在github 地址:https ...
随机推荐
- OC self注意事项
#import <Foundation/Foundation.h> @interface Person : NSObject - (void)test; + (void)test; - ( ...
- javaScript 变量提升 var let const,以及JS 的解析阶段和执行阶段
我们先来看一道面试题,大家猜想一下,下面这段代码,打印出来的结果是什么 var name = 'World!'; (function () { if (typeof name === 'undefin ...
- 小程序中的bindtap和catchtap的区别(交流QQ群:604788754)
bindtap绑定的节点,如果他的父节点也有绑定事件,点击之后就会出现冒泡. catchtap绑定的节点,如果他的父节点也有绑定事件,点击之后不会出现冒泡.
- git commit steps(1)
git commit steps: if you are a new git user , you may need to set # git config --global user.email & ...
- linux fdisk 添加硬盘,分区,挂载,永久挂载
具体步骤: 1.SSH登陆服务器: 2.列出所有硬盘: 命令:ll /dev/disk/by-path 我这里还有个sda 3.查看磁盘分区情况: 命令 :fdisk -l 最上面两部分表示我有两个物 ...
- MyEclipse 2017 CI 9 发布(附下载)
挑战全年最低价!MyEclipse线上狂欢继续!火热开启中>> 在进入年底之时,2017 CI 9是我们最大的版本发布之一.在新版本中,我们添加了对Angular 5和TypeScript ...
- struts2.properties
#action后缀struts.action.extension=action#上传文件的工作目录与文件的最大尺寸struts.multipart.saveDir=struts.multipart.m ...
- Bypass WAF
一.绕过命令执行: 很多WAF会限制参数字符不能为可以执行的命令,诸如ls.nc等,如果直接使用这些字符会直接被WAF拦截,但是可以通过这种的方式绕过这一限制 1.? 符号:这个符号表示条件测试,比如 ...
- $(function(){})与(function($){})(jquery)
$(function(){}) function中的代码在DOM加载完成后立即执行,比window.onload()更快,因为前者不需要等待图片加载完成. (function($){})(jquery ...
- 移动前端开发之viewport的深入理解 --- 待续
在移动设备上进行网页的重构或开发, 只有明白了viewport的概念 才能 响应 各种 不同分辨率 的移动设备 一.viewport的概念 通俗的讲,移动设备上的viewport就是设备的屏幕上能用 ...