Logback 整合 RabbitMQ 实现统一日志输出

一、前言

公司项目做了集群实现请求分流,由于线上或多或少会出现请求失败或系统异常,为了查看失败请求的日志信息,我们得将所有服务的日志文件都打开来进行问题的定位分析,操作起来非常麻烦。因此,我们开发组决定设计一套日志查看系统来解决上述问题。

二、实现思路

默认的,应用服务日志信息会保存在本地服务器的目录中,为了方便查看日志我们应该把多台服务器日志统一输出到一个日志文件中。

由于项目使用的 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 基础入门》 查看。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
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 依赖

列出主要依赖:

1
2
3
4
5
6
7
8
9
<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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
<?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 测试类

自定义异常:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
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;
	}

}

 复制

模拟打印日志:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
@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);
		}
		
	}
}

 复制

五、代码测试

执行启动类:

1
2
3
4
5
6
7
8
9
@EnableScheduling
@SpringBootApplication
public class RabbitmqTestApplication {

	public static void main(String[] args) {
		SpringApplication.run(RabbitmqTestApplication.class, args);
	}

}

 复制

执行结果如下图:

码运行的日志信息已经输出到指定日志文件中了。

补充

由于多台服务器的日志都打印到同一个文件,为了区分日志来源,我们还得需要打印出日志信息对应的主机 ip 地址。具体实现步骤如下:

  • 自定义日志转换器

需要继承 ClassicConverter 类

1
2
3
4
5
6
7
8
9
10
11
12
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 文件

以下只张贴关键配置信息

1
2
3
4
5
6
7
8
 <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>		
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
统一日志框架记录是指在应用程序中使用相同的日志框架,以便更好地管理和维护应用程序的日志记录。常见的日志框架有log4j、logback、slf4j等。 下面是一个使用log4j进行统一日志框架记录的代码示例: 1. 添加log4j依赖 在项目的pom.xml文件中添加log4j依赖: ```xml <dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>1.2.17</version> </dependency> ``` 2. 配置log4j 在项目的资源目录下创建log4j.properties文件,配置log4j的相关参数,例如: ```properties log4j.rootLogger=INFO, CONSOLE, FILE log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender log4j.appender.CONSOLE.Target=System.out log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout log4j.appender.CONSOLE.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %p %c{1}:%L - %m%n log4j.appender.FILE=org.apache.log4j.RollingFileAppender log4j.appender.FILE.File=./logs/app.log log4j.appender.FILE.MaxFileSize=5MB log4j.appender.FILE.MaxBackupIndex=10 log4j.appender.FILE.layout=org.apache.log4j.PatternLayout log4j.appender.FILE.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %p %c{1}:%L - %m%n ``` 上述配置文件定义了两个appender:CONSOLE和FILE。CONSOLE将日志输出到控制台,FILE将日志输出到文件中。 3. 使用log4j 在应用程序的代码中使用log4j进行日志记录,例如: ```java import org.apache.log4j.Logger; public class MyClass { private static final Logger logger = Logger.getLogger(MyClass.class); public void doSomething() { logger.info("Do something"); logger.debug("Debugging message"); logger.error("Error message"); } } ``` 在上述代码中,使用Logger.getLogger方法获取Logger对象,然后使用Logger对象进行日志记录。在这里,我们使用了info、debug和error三种级别的日志记录。 4. 运行应用程序 运行应用程序后,log4j将根据配置文件,将日志输出到控制台和文件中。在控制台中,会按照时间和级别的顺序输出日志信息,例如: ``` 2022-01-01 12:00:00 INFO MyClass:10 - Do something 2022-01-01 12:00:01 ERROR MyClass:12 - Error message ``` 在文件中,也会按照时间和级别的顺序输出日志信息,例如: ``` 2022-01-01 12:00:00 INFO MyClass:10 - Do something 2022-01-01 12:00:01 ERROR MyClass:12 - Error message ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值