日志同步到MySQLl数据库两种方式

第一种 通过 logback-spring.xml配置文件方式

项目为SpringBoot项目

application.yml配置文件

#logback日志参数
logback:
  path: /data/wxpublic/logs/
  zip.path: /data/wxpublic/logs/zip
  maxFileSize: 10MB
  maxHistory: 15
  totalSizeCap: 1000MB
  level: INFO

logback-spring.xml配置文件

<?xml version="1.0" encoding="UTF-8"?>


<!-- scan:当此属性设置为true时,配置文档如果发生改变,将会被重新加载,默认值为true -->
<!-- scanPeriod:设置监测配置文档是否有修改的时间间隔,如果没有给出时间单位,默认单位是毫秒。
	当scan为true时,此属性生效。默认的时间间隔为1分钟。 -->
<configuration scan="true">
	<!--通过在logback配置文件中引入yml或properties中的属性,从而实现通过yml或者properties配置实现logback属性配置。
	在logback-spring.xml文件中通过springProperty标签引用application-dev.yml的属性,
	注意是logback-spring.xml文件而不是logback.xml文件,
	因为logback.xml文件早于application.yml加载,logback-spring.xml文件晚于application.yml文件加载。
	-->
	<springProperty scope="context" name="logback.path" source="logback.path" />
	<springProperty scope="context" name="logback.zip.path" source="logback.zip.path" />
	<springProperty scope="context" name="logback.maxFileSize" source="logback.maxFileSize" />
	<springProperty scope="context" name="logback.totalSizeCap" source="logback.totalSizeCap" />
	<springProperty scope="context" name="logback.maxHistory" source="logback.maxHistory" />
	<springProperty scope="context" name="logback.level" source="logback.level" />

	<!-- 控制台日志配置 --><!--1. 输出到控制台-->
	<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
		<encoder>
			<!-- 格式化 -->
			<pattern>%d{
    
    yyyy-MM-dd HH:mm:ss} [%p] [%t] %c{
    
    36} - %m%n</pattern>
			<!-- 设置字符集 -->
			<charset>UTF-8</charset>
		</encoder>
	</appender>

	<!-- info级别日志控制 --><!--2. 输出到文档-->
	<appender name="FILE_INFO" class="ch.qos.logback.core.rolling.RollingFileAppender">
		<!-- 文件路径 -->
		<file>${
    
    logback.path}/info.log</file>
		<!-- 是否追加 默认为true -->
		<append>true</append>
		<!-- 滚动策略 日期+大小 策略 -->
		<rollingPolicy
				class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
			<fileNamePattern>${
    
    logback.zip.path}/%d{
    
    yyyy-MM-dd}/info/info-%i.zip</fileNamePattern>
			<!-- 单个日志大小 -->
			<maxFileSize>${
    
    logback.maxFileSize}</maxFileSize>
			<!-- 日志保存周期 -->
			<maxHistory>${
    
    logback.maxHistory}</maxHistory>
			<!-- 总大小 -->
			<totalSizeCap>${
    
    logback.totalSizeCap}</totalSizeCap>
		</rollingPolicy>
		<!-- 格式化 -->
		<encoder>
			<pattern>%d{
    
    yyyy-MM-dd HH:mm:ss} [%p] [%t] %c{
    
    36} - %m%n</pattern>
		</encoder>
		<!-- 级别过滤 -->
		<filter class="ch.qos.logback.classic.filter.LevelFilter">
			<level>INFO</level>
			<onMatch>ACCEPT</onMatch>
			<onMismatch>DENY</onMismatch>
		</filter>
	</appender>

	<!-- warn级别日志控制 -->
	<appender name="WARN_INFO"
			  class="ch.qos.logback.core.rolling.RollingFileAppender">
		<!-- 文件路径 -->
		<file>${
    
    logback.path}/warn.log</file>
		<!-- 是否追加 默认为true -->
		<append>true</append>
		<!-- 滚动策略 日期+大小 策略 -->
		<rollingPolicy
				class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
			<!-- 活动文件的名字会根据fileNamePattern的值,每隔一段时间改变一次 -->
			<fileNamePattern>${
    
    logback.zip.path}/%d{
    
    yyyy-MM-dd}/warn/warn-%i.zip</fileNamePattern>
			<!-- 单个日志大小  maxFileSize:这是活动文件的大小,默认值是10MB,测试时可改成1KB看效果 -->
			<maxFileSize>${
    
    logback.maxFileSize}</maxFileSize>
			<!--  注意,maxHistory代表的是最大存档文件的数量,不是存档期限。达到阈值时,删除最老的日志 -->
			<maxHistory>${
    
    logback.maxHistory}</maxHistory>
			<!-- 总大小 -->
			<totalSizeCap>${
    
    logback.totalSizeCap}</totalSizeCap>
		</rollingPolicy>
		<!-- 格式化 -->
		<encoder>
			<pattern>%d{
    
    yyyy-MM-dd HH:mm:ss} [%p] [%t] %c{
    
    36} - %m%n</pattern>
		</encoder>
		<!-- 级别过滤 -->
		<filter class="ch.qos.logback.classic.filter.LevelFilter">
			<level>WARN</level>
			<onMatch>ACCEPT</onMatch>
			<onMismatch>DENY</onMismatch>
		</filter>
	</appender>

	<!-- ERROR级别日志控制 -->
	<appender name="ERROR_INFO" class="ch.qos.logback.core.rolling.RollingFileAppender">
		<!-- 文件路径 -->
		<file>${
    
    logback.path}/error.log</file>
		<!-- 是否追加 默认为true -->
		<append>true</append>
		<!-- 滚动策略 日期+大小 策略 -->
		<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
			<fileNamePattern>${
    
    logback.zip.path}/%d{
    
    yyyy-MM-dd}/error/error-%i.zip</fileNamePattern>
			<!-- 单个日志大小 -->
			<maxFileSize>${
    
    logback.maxFileSize}</maxFileSize>
			<!-- 日志保存周期 -->
			<maxHistory>${
    
    logback.maxHistory}</maxHistory>
			<!-- 总大小 -->
			<totalSizeCap>${
    
    logback.totalSizeCap}</totalSizeCap>
		</rollingPolicy>
		<!-- 格式化 -->
		<encoder>
			<pattern>%d{
    
    yyyy-MM-dd HH:mm:ss} [%p] [%t] %c{
    
    36} - %m%n</pattern>
		</encoder>
		<!-- 级别过滤 -->
		<filter class="ch.qos.logback.classic.filter.LevelFilter">
			<level>ERROR</level>
			<onMatch>ACCEPT</onMatch>
			<onMismatch>DENY</onMismatch>
		</filter>
	</appender>
	<!-- 将日志写入数据库 -->
	<appender name="DB-CLASSIC-MYSQL-POOL" class="ch.qos.logback.classic.db.DBAppender">
		<connectionSource class="ch.qos.logback.core.db.DataSourceConnectionSource">
			<dataSource class="org.apache.commons.dbcp.BasicDataSource">
				<driverClassName>com.mysql.jdbc.Driver</driverClassName>
				<url>jdbc:mysql://116.62.13.104:3306/countdown?characterEncoding=UTF-8</url>
				<username>root</username>
				<password>123456</password>
			</dataSource>
		</connectionSource>
		<!--这里设置日志级别为error   info-->
		<filter class="ch.qos.logback.classic.filter.LevelFilter">
			<level>error</level>
			<onMatch>ACCEPT</onMatch>
			<onMismatch>DENY</onMismatch>
		</filter>
	</appender>

	<root level="${logback.level}">
		<appender-ref ref="CONSOLE" />
		<appender-ref ref="FILE_INFO" />
		<appender-ref ref="WARN_INFO" />
		<appender-ref ref="ERROR_INFO" />
		<appender-ref ref="DB-CLASSIC-MYSQL-POOL" />
	</root>

</configuration>

在这里插入图片描述

MySQL建表语句(固定,直接CV运行)

BEGIN;
DROP TABLE IF EXISTS logging_event_property;
DROP TABLE IF EXISTS logging_event_exception;
DROP TABLE IF EXISTS logging_event;
COMMIT;
 
BEGIN;
CREATE TABLE logging_event 
  (
    timestmp         BIGINT NOT NULL,
    formatted_message  TEXT NOT NULL,
    logger_name       VARCHAR(254) NOT NULL,
    level_string      VARCHAR(254) NOT NULL,
    thread_name       VARCHAR(254),
    reference_flag    SMALLINT,
    arg0              VARCHAR(254),
    arg1              VARCHAR(254),
    arg2              VARCHAR(254),
    arg3              VARCHAR(254),
    caller_filename   VARCHAR(254) NOT NULL,
    caller_class      VARCHAR(254) NOT NULL,
    caller_method     VARCHAR(254) NOT NULL,
    caller_line       CHAR(4) NOT NULL,
    event_id          BIGINT NOT NULL AUTO_INCREMENT PRIMARY KEY
  );
COMMIT;
 
 
BEGIN;
CREATE TABLE logging_event_property
  (
    event_id       BIGINT NOT NULL,
    mapped_key        VARCHAR(254) NOT NULL,
    mapped_value      TEXT,
    PRIMARY KEY(event_id, mapped_key),
    FOREIGN KEY (event_id) REFERENCES logging_event(event_id)
  );
COMMIT;
 
 
BEGIN;
CREATE TABLE logging_event_exception
  (
    event_id         BIGINT NOT NULL,
    i                SMALLINT NOT NULL,
    trace_line       VARCHAR(254) NOT NULL,
    PRIMARY KEY(event_id, i),
    FOREIGN KEY (event_id) REFERENCES logging_event(event_id)
  );
COMMIT;

在这里插入图片描述
注意:
此处的建表语句是固定的,原因就是我们配置文件中 appender 中指定的类是ch.qos.logback.classic.db.DBAppender
在这里插入图片描述
打开这个类可以看到:

在DBAppender类中的start()方法,可以看到insertSQL是通过SQLBuilder的buildInsertSQl方法构建的SQL语句
在这里插入图片描述
点进这个类可以看到将日志信息插入到数据的SQL语句就是在这里构建的,所以说不需要我们写SQL语句,但是需要将用到的数据库表建好。
在这里插入图片描述
点进其中的TableName或者ColumnName可以看到对应的类名和字段名。
在这里插入图片描述
在这里插入图片描述

自定义建表语句

如果想要自己创建自己的数据库表,自己定义字段
就需要把配置文件中的appender标签中的class修改成我们自己的类(需要继承DBAppenderBase),即重写DBAppender类。

自定义建表sql

CREATE TABLE `logs` (
  `id` BIGINT(20) NOT NULL AUTO_INCREMENT,
  `message` VARCHAR(300) NOT NULL COMMENT '内容',
  `level_string` VARCHAR(254) NOT NULL COMMENT '级别',
  `created_time` DATETIME NOT NULL COMMENT '时间',
  `logger_name` VARCHAR(300) NOT NULL COMMENT '全类名',
  PRIMARY KEY (`id`)
) ENGINE=INNODB DEFAULT CHARSET=utf8 COMMENT='自定义日志记录表'

重写DBAppender

package com.wx.util;

import ch.qos.logback.classic.spi.CallerData;
import ch.qos.logback.classic.spi.ILoggingEvent;
import ch.qos.logback.core.db.DBAppenderBase;
import org.springframework.context.annotation.Configuration;

import java.lang.reflect.Method;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.sql.Timestamp;

@Configuration
public class LogDBAppender extends DBAppenderBase<ILoggingEvent> {
    
    

    protected static final Method GET_GENERATED_KEYS_METHOD;
    //插入sql
    protected String insertSQL;
    // message 日志内容
    static final int MESSAGE = 1;
    // level_string
    static final int LEVEL_STRING = 2;
    // created_time 时间
    static final int CREATE_TIME = 3;
    // logger_name 全类名
    static final int LOGGER_NAME = 4;

    static final StackTraceElement EMPTY_CALLER_DATA = CallerData.naInstance();

    static {
    
    
        // PreparedStatement.getGeneratedKeys() method was added in JDK 1.4
        Method getGeneratedKeysMethod;
        try {
    
    
            // the
            getGeneratedKeysMethod = PreparedStatement.class.getMethod("getGeneratedKeys", (Class[]) null);
        } catch (Exception ex) {
    
    
            getGeneratedKeysMethod = null;
        }
        GET_GENERATED_KEYS_METHOD = getGeneratedKeysMethod;
    }

    @Override
    public void start() {
    
    
        // 将写好的sql语句赋值给insertSQL
        insertSQL = buildInsertSQL();
        super.start();
    }

    // 自己写新增sql语句
    private static String buildInsertSQL() {
    
    
        return "INSERT INTO `logs`(`message`,`level_string`,`created_time`,`logger_name`)" +
                "VALUES (?,?,?,?)";
    }

    @Override
    protected Method getGeneratedKeysMethod() {
    
    
        return GET_GENERATED_KEYS_METHOD;
    }

    @Override
    protected String getInsertSQL() {
    
    
        return insertSQL;
    }

    /**
     * 主要修改的方法
     *
     * @param stmt
     * @param event
     * @throws SQLException
     */
    private void bindLoggingEventWithInsertStatement(PreparedStatement stmt, ILoggingEvent event) throws SQLException {
    
    
        // event.getFormattedMessage() 日志打印内容
        String message = event.getFormattedMessage();
        // 如果只想存储自己打印的日志,可以这样写日志:logger.info("- XXXX")
        if(message.startsWith("-")){
    
     // 判断日志消息首字母为 - 的日志,记录到数据库表
            stmt.setString(MESSAGE, message);
            // event.getLevel().toString() 日志级别
            stmt.setString(LEVEL_STRING, event.getLevel().toString());
            // new Timestamp(event.getTimeStamp()) 时间
            stmt.setTimestamp(CREATE_TIME, new Timestamp(event.getTimeStamp()));
            // event.getLoggerName() 全类名
            stmt.setString(LOGGER_NAME, event.getLoggerName());
        }

    }

    @Override
    protected void subAppend(ILoggingEvent eventObject, Connection connection, PreparedStatement statement) throws Throwable {
    
    
        bindLoggingEventWithInsertStatement(statement, eventObject);
        // This is expensive... should we do it every time?
        int updateCount = statement.executeUpdate();
        if (updateCount != 1) {
    
    
            addWarn("Failed to insert loggingEvent");
        }
    }

    @Override
    protected void secondarySubAppend(ILoggingEvent eventObject, Connection connection, long eventId) throws Throwable {
    
    
    }
}

修改logback-spring.xml配置文件
在这里插入图片描述

效果

在这里插入图片描述

扫描二维码关注公众号,回复: 12076590 查看本文章

第二种 通过Logstash方式 同步

Filebeat

Filebeat是go语言开发的,一个轻量级的日志收集的工具,消耗更少的cpu 和 内存。
通用设计是 filebeat读取日志,输出到logstash,经过logstash解析后,输出到 elasticsearch

Logstash

Logstash是一款轻量级的日志搜集处理框架,可以方便的把分散的、多样化的日志搜集起来,并进行自定义的处理,然后传输到指定的位置,比如某个服务器或者文件。

待续。。。

猜你喜欢

转载自blog.csdn.net/DreamsArchitects/article/details/109097271