logback 将日志保存CSV文件

背景

公司业务,要将数据要做本地备份记录,开始直接保存json格式,但是太占用存储,所以使用csv格式保存。

思路

1、使用csvWriter ,数据来时,将数据写入本地
不足:
如果每次数据来临时,创建一个csvWriter性能有影响,批量写入也可以,这不是主要原因。主要原因是,需要考虑什么时候创建csv文件,什么时候关闭csv流,当项目升级时,也要关闭流。注意的点太多(放弃)

2、csv其实就是一个文本,每行数据就是用逗号分割,我们可以将数据逗号分割好,直接使用info(data)来记录数据。
难点是,如何将标头写入文件。

自定义Appender、Encoder

xml文件

<appender name="USER_LOG" class="com.sjy.logback.CsvRollingFileAppender">
        <encoder class="com.sjy.logback.CsvPatternLayoutEncoder">
            <fileHeader>time,data,user,urlfileHeader>
            <charset>UTF-8charset>
            <pattern>%msg%npattern>
        encoder>
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <FileNamePattern>/var/log/user-data.%d{yyyy-MM-dd}.csvFileNamePattern>
            <MaxHistory>7MaxHistory>
        rollingPolicy>
    appender>
<logger name="userLogger" level="INFO" additivity="false">
        <appender-ref ref="USER_LOG" />
    logger>

CsvRollingFileAppender.java

import ch.qos.logback.core.FileAppender;
import ch.qos.logback.core.encoder.Encoder;
import ch.qos.logback.core.recovery.ResilientFileOutputStream;
import ch.qos.logback.core.rolling.RollingFileAppender;
import ch.qos.logback.core.util.FileUtil;

import java.io.File;
import java.io.IOException;

/*
判断文件是否存在,如果存在,将header 去除,如果不存在添加fileHeader
 */
public class CsvRollingFileAppender<E> extends RollingFileAppender<E> {
    @Override
    public void openFile(String file_name) throws IOException {
        lock.lock();
        try {
            File file = new File(file_name);
            boolean result = FileUtil.createMissingParentDirectories(file);
            if (!result) {
                addError("Failed to create parent directories for [" + file.getAbsolutePath() + "]");
            }

            ResilientFileOutputStream resilientFos = new ResilientFileOutputStream(file, append, FileAppender.DEFAULT_BUFFER_SIZE);
            resilientFos.setContext(context);
            CsvPatternLayoutEncoder encoder = (CsvPatternLayoutEncoder) this.getEncoder();
            String fileHeader = null;
            // 文件是否存在
            boolean isNew = !file.exists() || file.length() <= 0;
            if (!isNew) {
                // 设置null
                fileHeader = encoder.getFileHeader();
                encoder.setPatternLayoutFileHeader(null);
            }
            // 写入文件
            setOutputStream(resilientFos);
            if (!isNew) {
                encoder.setPatternLayoutFileHeader(fileHeader);
            }
        } finally {
            lock.unlock();
        }
    }
}

CsvPatternLayoutEncoder .java

import ch.qos.logback.classic.PatternLayout;
import ch.qos.logback.classic.spi.ILoggingEvent;
import ch.qos.logback.core.pattern.PatternLayoutEncoderBase;

public class CsvPatternLayoutEncoder extends PatternLayoutEncoderBase<ILoggingEvent> {
    private String fileHeader;
    private PatternLayout patternLayout;
    @Override
    public void start() {
        patternLayout = new PatternLayout();
        patternLayout.setContext(context);
        patternLayout.setPattern(getPattern());
        patternLayout.setFileHeader(getFileHeader());
        patternLayout.setOutputPatternAsHeader(outputPatternAsHeader);
        patternLayout.start();
        this.layout = patternLayout;
        super.start();
    }

    public String getFileHeader() {
        return fileHeader;
    }

    public void setFileHeader(String fileHeader) {
        this.fileHeader = fileHeader;
    }

    public void setPatternLayoutFileHeader(String fileHeader) {
        patternLayout.setFileHeader(fileHeader);
    }
}
private static Logger log = LoggerFactory.getLogger("userLogger");
// 写入文件
public void logToFile() {
    log.info(time+","+data+","+user+","+url);
}

注意事项

  1. 因为CSV是一个用逗号分割的文本,所以在datauser数据中不要有逗号

你可能感兴趣的:(logback,spring,boot,java)