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>     

原文地址:https://www.cnblogs.com/moonlightL/p/10440047.html

时间: 2024-10-02 14:39:03

Logback 整合 RabbitMQ 实现统一日志输出的相关文章

logback整合控制台sysout输出到日志文件

项目中有些地方日志打印是通过sysout的,但是之前logback的操作只能输出info,error这些内容,问题不大,下面的操作可以将控制台的输出打印到日志文件里面 (项目是基于springboot的) 引入相关依赖 <!-- https://mvnrepository.com/artifact/uk.org.lidalia/sysout-over-slf4j --> <dependency> <groupId>uk.org.lidalia</groupId&g

log4j和logback的冲突导致日志输出异常

前一阵在在项目中碰到一个日志问题.工程使用的是log4j,log4j.xml中也配置了工程日志路径和策略,并把日志级别定为warn.但不管是测试环境还是线上环境,都发现除了应用自身的日志,以及指定输出日志,工程中依赖的包输出的日志都打到了tomcat自身的日志文件中,并且debug的日志也一并输出,导致tomcat的日志文件增长非常快,没几天就把服务器空间占满.线上服务器还好,有脚本自动清理,测试环境的服务器直接宕机. 最初,以为是tomcat配置问题,找到PE检查脚本,发现跟tomcat并无直

logback KafkaAppender 写入Kafka队列,集中日志输出.

为了减少应用服务器对磁盘的读写,以及可以集中日志在一台机器上,方便使用ELK收集日志信息,所以考虑做一个jar包,让应用集中输出日志 网上搜了一圈,只发现有人写了个程序在github 地址:https://github.com/johnmpage/logback-kafka 本来打算引用一下这个jar就完事了,没想到在pom里下不下来,只好把源码下了,拷贝了代码过来,自己修改一下. 首先,安装一个Kafka,作为一个懒得出神入化得程序员,我选择的安装方式是 启动zookeeper容器 docke

9 个技巧,解决 K8s 中的日志输出问题

作者 | 元乙??阿里云存储服务技术专家 导读:近年来,越来越多的同学咨询如何为 Kubernetes 构建一个日志系统,或者是来求助在此过程中遇到一系列问题如何解决,授人以鱼不如授人以渔,于是作者想把这些年积累的经验以文章的形式发出来,让看到文章的同学少走弯路.K8s 日志系列文章内容偏向落地实操以及经验分享,且内容会随着技术的迭代而不定期更新,本文为该系列文章的第 3 篇. 第一篇:<6 个 K8s 日志系统建设中的典型问题,你遇到过几个?> 第二篇:<一文看懂 K8s 日志系统设计

Java项目构建基础之统一日志收集

统一日志收集 日志是追踪错误定位问题的关键,尤其在生产环境中,需要及时修复热部署,不会提供开发者debug的环境,此时日志将会是最快解决问题的关键 Logback 关于logback的配置和介绍,可以参考官网或推荐博客glmapper的logback博客,logback-spring.xml配置文件 https://blog.csdn.net/xu_san_duo/article/details/80364600 配置 以下直接贴出配置信息,介绍信息可以直接参考备注 <?xml version=

JAVA中使用log4j及slf4j进行日志输出的方法

JAVA中输出日志比较常用的是log4j,这里讲下log4j的配置和使用方法,以及slf4j的使用. 一.下载log4j的架包,并导入项目中,如下: 二.创建log4j.properties配置文件 1.log4j配置文件的位置: (1)如果是java project项目,则在项目的根目录下创建log4j.properties而不是在src目录下. (2)如果是java web项目,则在src目录下创建log4j.properties配置文件,因为这个时候tomcat会去默认的加载这个配置文件,

使用Spring进行统一日志管理 + 统一异常管理

统一日志和异常管理配置好后,SSH项目中,代码以往散落的log.info() 和 try..catch..finally 再也不见踪影! 统一日志异常实现类: [java] view plain copy package com.pilelot.web.util; import org.apache.log4j.Logger; import org.springframework.aop.ThrowsAdvice; import org.springframework.dao.DataAcces

Java学习-046-日志抓取合并后排序问题解决方案之 --- log4j 二次定制,实现日志输出添加延时10ms

自3月25至今,已经好久没有写学习日志了,今天在写日志抓取合并的小方法,发现抓取后的日志并米有依据系统执行的日志顺序排序.日志抓取排列逻辑如下: 通过日志标识,从各个日志文件(例如 use.log,error.log 等)中获取所需日志列表 合并日志列表 升序排序 输出日志报告 结果最后获取日志信息后,发现实际产出结果与预期结果不相符,如下所示: 1 2016-04-10 22:54:23,042 - INFO - [main] [cn.ffp.autotest.api.report.Repor

基于ActiveMQ的统一日志服务

概述 以ActiveMQ + Log4j + Spring的技术组合,实现基于消息队列的统一日志服务. 参考:Spring+Log4j+ActiveMQ实现远程记录日志——实战+分析 与参考文章的比较 1. 更新了技术的版本    e.g. Spring升级到4.2.0,ActiveMQ升级到5.13.2 2. 更新了依赖    e.g. 使用activemq-client 5.13.2替换activemq-core最高版本是5.7.0,并取消了多余的spring-jms依赖 3. 精简了配置