logback实时记录日志 保存入库

本文介绍了一种收集系统日志并异步存入数据库的方法,通过自定义LogAd类继承ConsoleAppender,重写append方法来捕获log.info等日志信息,再将这些信息存入阻塞队列,最后通过定时任务批量处理队列中的日志,实现高效日志管理。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

需求:收集系统中打印的日志,例如 log.info(), log.warn(),log.infor(),log.debug()等等,并且做入库处理。

    public static void main(String[] args) {
        System.setProperty("es.set.netty.runtime.available.processors", "false");
        SpringApplication.run(DelayqueuetestApplication.class, args);
    }
    @Override
    public void run(String... args) throws Exception {
        log.info("哈哈哈哈哈哈info");
        log.warn("哈哈哈哈哈哈warn");
        log.debug("哈哈哈哈哈哈debug");
        log.error("哈哈哈哈哈哈error");
    }
复制代码

方案具体实现:利用logback自带的appender

logback自带的appender
ConsoleAppender    将日志输出到控制台

FileAppender    将日志输出到文件

RollingFileAppender    滚动文件生成,按条件生成不同文件,配合TriggeringPolicy使用

SocketAppender    输出日志到远程实例中,明文传输

SSLSocketAppender    输出日志到远程实例中,密文传输

SMTPAppender    将日志输出到邮件

DBAppender    日志事件插入数据库中,需要提前创建表

SyslogAppender    是一个SocketAppender,将日志输出到远程系统日志

SiftingAppender    可基于任何给定的实时属性分开(或者筛选)日志,如基于用户会话分开日志事件

AmqpAppender    将日志输出到MQ服务中  
复制代码

xml配置中其中class指定为logAd的类全路径

 <appender name="STDOUT" class="com.example.delayqueuetest.log.LogAd">
        <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> 
复制代码

让其继承ConsoleAppender类,重写append()方法,这样系统运行后,

如果遇到打印log.info类似语句 就会执行append()方法。

import ch.qos.logback.classic.spi.ILoggingEvent;
import ch.qos.logback.core.ConsoleAppender;
import com.alibaba.fastjson.JSON;
import com.example.delayqueuetest.model.Log;

/**
 *  继承ConsoleAppender 重写append方法
 *  收集系统中所有的 log.info error warn debug 等打印语句 然后入库
 *  @date 2019年5月9日
 *  @author dongzhuo
 */
public class LogAd extends ConsoleAppender<ILoggingEvent> {
    @Override
    protected void append(ILoggingEvent eventObject) {
        Log log = new Log(eventObject.getLoggerName(), eventObject.getMessage(), eventObject.getThreadName(), String.valueOf(eventObject.getTimeStamp()),eventObject.getLevel().toString());
          //添加到阻塞队列
        DataContext.tempLogQueue.add(log) ;
        System.err.println(JSON.toJSONString(log,true));
    }
}
复制代码

其中IloggingEvent类详细参数如下:

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//

package ch.qos.logback.classic.spi;

import ch.qos.logback.classic.Level;
import ch.qos.logback.core.spi.DeferredProcessingAware;
import java.util.Map;
import org.slf4j.Marker;

public interface ILoggingEvent extends DeferredProcessingAware {
    String getThreadName();

    Level getLevel();

    String getMessage();

    Object[] getArgumentArray();

    String getFormattedMessage();

    String getLoggerName();

    LoggerContextVO getLoggerContextVO();

    IThrowableProxy getThrowableProxy();

    StackTraceElement[] getCallerData();

    boolean hasCallerData();

    Marker getMarker();

    Map<String, String> getMDCPropertyMap();

    /** @deprecated */
    Map<String, String> getMdc();

    long getTimeStamp();

    void prepareForDeferredProcessing();
}

复制代码

Log类如下:

@Data
@AllArgsConstructor
public class Log {
    /**
     * 类的全路径名称
     */
    private String loggerName;
    /**
     * 打印的消息
     */
    private String message;
    /**
     * 线程名称
     */
    private String threadName;
    /**
     * 时间戳 日志打印的时间
     */
    private String timeStamp;
    /**
     * 日志打印级别
     */
    private String level;
}
复制代码

控制台打印如下

{
   "level":"INFO",
   "loggerName":"com.example.delayqueuetest.DelayqueuetestApplication",
   "message":"哈哈哈哈哈哈info",
   "threadName":"main",
   "timeStamp":"1557389007586"
}
{
   "level":"WARN",
   "loggerName":"com.example.delayqueuetest.DelayqueuetestApplication",
   "message":"哈哈哈哈哈哈warn",
   "threadName":"main",
   "timeStamp":"1557389007586"
}
{
   "level":"ERROR",
   "loggerName":"com.example.delayqueuetest.DelayqueuetestApplication",
   "message":"哈哈哈哈哈哈error",
   "threadName":"main",
   "timeStamp":"1557389007586"
}
复制代码

知道以上信息,就可以做后续的操作了,保存数据库即可,数据库设计省略。目前线上系统 是拿到日志实体 放入一个阻塞队列,然后开启定时器 对这个队列做take操作,take()自带阻塞功能,很好的实现异步保存日志功能。

@Configuration
@EnableScheduling
public class LogTask {

    @Autowired
    private LogRepository logRes;
    /**
     *  接着上一次程序跑完后的5秒后执行
     */
    @Scheduled(fixedDelay= 5000) 
    public void log(){
        /**
         * 日志处理
         */
        Log log = null ;
        while((log = DataContext.tempLogQueue.poll()) != null){
            SystemConfig systemConfig = UKTools.getSystemConfig();
            if(systemConfig!=null && systemConfig.isSavelog()) { 
                logRes.save(log) ;
            }
        }
    }
}
复制代码

其中队列为:在DataContext类中定义了阻塞队列。

public static BlockingQueue<Log> tempLogQueue = new LinkedBlockingQueue<>();
复制代码

文章参考 www.cnblogs.com/warking/p/5…

转载于:https://juejin.im/post/5cda3100e51d45475d5e8df4

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值