文章目录
第一种 通过 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是一款轻量级的日志搜集处理框架,可以方便的把分散的、多样化的日志搜集起来,并进行自定义的处理,然后传输到指定的位置,比如某个服务器或者文件。
待续。。。