logback实时记录日志 保存入库

Posted 独行侠飞

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了logback实时记录日志 保存入库相关的知识,希望对你有一定的参考价值。


需求:收集系统中打印的日志,例如 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<>();


文章参考

https://www.cnblogs.com/warking/p/5710303.html



This browser does not support music or audio playback. Please play it in WeChat or another browser.

以上是关于logback实时记录日志 保存入库的主要内容,如果未能解决你的问题,请参考以下文章

logback日志的快速使用

Logback的浪漫: 记录每一个瞬间

无侵入!巧用logback扩展,见识它的强大

Spring Boot配置保存日志文件

SLF4J + logback 实现日志输出和记录

最全最详细Logback高级讲解