博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
springboot+logback日志异步数据库
阅读量:6293 次
发布时间:2019-06-22

本文共 14639 字,大约阅读时间需要 48 分钟。

logback.xml配置文件:

%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{50} - %msg%n
${LOG_HOME}/%d{yyyy-MM-dd}/MIXPAY_%d{yyyy-MM-s}.log
50
%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{50} - %msg%n
50MB
DB
ACCEPT
DENY
net.sf.log4jdbc.DriverSpy
jdbc:log4jdbc:mysql://127.0.0.1:3306/dbname?characterEncoding=UTF-8
root
123456
  
  
true
复制代码

异步日志的核心配置如下:

DB
ACCEPT
DENY
net.sf.log4jdbc.DriverSpy
jdbc:log4jdbc:mysql://127.0.0.1:3306/dbname?characterEncoding=UTF-8
root
123456
复制代码

自定义 LogDBAppender (Appender是logback框架中最重要的组件之一)

import ch.qos.logback.classic.db.DBHelper;import ch.qos.logback.classic.db.names.ColumnName;import ch.qos.logback.classic.db.names.DBNameResolver;import ch.qos.logback.classic.db.names.DefaultDBNameResolver;import ch.qos.logback.classic.db.names.TableName;import ch.qos.logback.classic.spi.CallerData;import ch.qos.logback.classic.spi.ILoggingEvent;import ch.qos.logback.core.db.DBAppenderBase; import java.lang.reflect.Method;import java.sql.Connection;import java.sql.PreparedStatement;import java.sql.SQLException;import java.util.HashMap;import java.util.Map; /** * @Title: LogDBAppender.java * @Description: TODO(日志持久化配置) * @Author: 爱飘de小子  上午9:43 */public class LogDBAppender extends DBAppenderBase
{ protected String insertSQL; protected static final Method GET_GENERATED_KEYS_METHOD; private DBNameResolver dbNameResolver; static final int TIMESTMP_INDEX = 1; static final int FORMATTED_MESSAGE_INDEX = 2; static final int LOGGER_NAME_INDEX = 3; static final int LEVEL_STRING_INDEX = 4; static final int THREAD_NAME_INDEX = 5; static final int REFERENCE_FLAG_INDEX = 6; static final int ARG0_INDEX = 7; static final int ARG1_INDEX = 8; static final int ARG2_INDEX = 9; static final int ARG3_INDEX = 10; static final int CALLER_FILENAME_INDEX = 11; static final int CALLER_CLASS_INDEX = 12; static final int CALLER_METHOD_INDEX = 13; static final int CALLER_LINE_INDEX = 14; static final int EVENT_ID_INDEX = 15; 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; } public void setDbNameResolver(DBNameResolver dbNameResolver) { this.dbNameResolver = dbNameResolver; } @Override public void start() { if (dbNameResolver == null) dbNameResolver = new DefaultDBNameResolver(); insertSQL = buildInsertSQL(dbNameResolver); super.start(); } @Override protected void subAppend(ILoggingEvent event, Connection connection, PreparedStatement insertStatement) throws Throwable { bindLoggingEventWithInsertStatement(insertStatement, event); bindLoggingEventArgumentsWithPreparedStatement(insertStatement, event.getArgumentArray()); // This is expensive... should we do it every time? bindCallerDataWithPreparedStatement(insertStatement, event.getCallerData()); int updateCount = insertStatement.executeUpdate(); if (updateCount != 1) { addWarn("Failed to insert loggingEvent"); } } @Override protected void secondarySubAppend(ILoggingEvent event, Connection connection, long eventId) throws Throwable { Map
mergedMap = mergePropertyMaps(event); //insertProperties(mergedMap, connection, eventId); // if (event.getThrowableProxy() != null) {// insertThrowable(event.getThrowableProxy(), connection, eventId);// } } void bindLoggingEventWithInsertStatement(PreparedStatement stmt, ILoggingEvent event) throws SQLException { stmt.setLong(TIMESTMP_INDEX, event.getTimeStamp()); stmt.setString(FORMATTED_MESSAGE_INDEX, event.getFormattedMessage()); stmt.setString(LOGGER_NAME_INDEX, event.getLoggerName()); stmt.setString(LEVEL_STRING_INDEX, event.getLevel().toString()); stmt.setString(THREAD_NAME_INDEX, event.getThreadName()); stmt.setShort(REFERENCE_FLAG_INDEX, DBHelper.computeReferenceMask(event)); } void bindLoggingEventArgumentsWithPreparedStatement(PreparedStatement stmt, Object[] argArray) throws SQLException { int arrayLen = argArray != null ? argArray.length : 0; for (int i = 0; i < arrayLen && i < 4; i++) { stmt.setString(ARG0_INDEX + i, asStringTruncatedTo254(argArray[i])); } if (arrayLen < 4) { for (int i = arrayLen; i < 4; i++) { stmt.setString(ARG0_INDEX + i, null); } } } String asStringTruncatedTo254(Object o) { String s = null; if (o != null) { s = o.toString(); } if (s == null) { return null; } if (s.length() <= 254) { return s; } else { return s.substring(0, 254); } } void bindCallerDataWithPreparedStatement(PreparedStatement stmt, StackTraceElement[] callerDataArray) throws SQLException { StackTraceElement caller = extractFirstCaller(callerDataArray); stmt.setString(CALLER_FILENAME_INDEX, caller.getFileName()); stmt.setString(CALLER_CLASS_INDEX, caller.getClassName()); stmt.setString(CALLER_METHOD_INDEX, caller.getMethodName()); stmt.setString(CALLER_LINE_INDEX, Integer.toString(caller.getLineNumber())); } private StackTraceElement extractFirstCaller(StackTraceElement[] callerDataArray) { StackTraceElement caller = EMPTY_CALLER_DATA; if (hasAtLeastOneNonNullElement(callerDataArray)) caller = callerDataArray[0]; return caller; } private boolean hasAtLeastOneNonNullElement(StackTraceElement[] callerDataArray) { return callerDataArray != null && callerDataArray.length > 0 && callerDataArray[0] != null; } Map
mergePropertyMaps(ILoggingEvent event) { Map
mergedMap = new HashMap
(); // we add the context properties first, then the event properties, since // we consider that event-specific properties should have priority over // context-wide properties. Map
loggerContextMap = event.getLoggerContextVO().getPropertyMap(); Map
mdcMap = event.getMDCPropertyMap(); if (loggerContextMap != null) { mergedMap.putAll(loggerContextMap); } if (mdcMap != null) { mergedMap.putAll(mdcMap); } return mergedMap; } @Override protected Method getGeneratedKeysMethod() { return GET_GENERATED_KEYS_METHOD; } @Override protected String getInsertSQL() { return insertSQL; } static String buildInsertSQL(DBNameResolver dbNameResolver) { StringBuilder sqlBuilder = new StringBuilder("INSERT INTO "); sqlBuilder.append(dbNameResolver.getTableName(TableName.LOGGING_EVENT)).append(" ("); sqlBuilder.append(dbNameResolver.getColumnName(ColumnName.TIMESTMP)).append(", "); sqlBuilder.append(dbNameResolver.getColumnName(ColumnName.FORMATTED_MESSAGE)).append(", "); sqlBuilder.append(dbNameResolver.getColumnName(ColumnName.LOGGER_NAME)).append(", "); sqlBuilder.append(dbNameResolver.getColumnName(ColumnName.LEVEL_STRING)).append(", "); sqlBuilder.append(dbNameResolver.getColumnName(ColumnName.THREAD_NAME)).append(", "); sqlBuilder.append(dbNameResolver.getColumnName(ColumnName.REFERENCE_FLAG)).append(", "); sqlBuilder.append(dbNameResolver.getColumnName(ColumnName.ARG0)).append(", "); sqlBuilder.append(dbNameResolver.getColumnName(ColumnName.ARG1)).append(", "); sqlBuilder.append(dbNameResolver.getColumnName(ColumnName.ARG2)).append(", "); sqlBuilder.append(dbNameResolver.getColumnName(ColumnName.ARG3)).append(", "); sqlBuilder.append(dbNameResolver.getColumnName(ColumnName.CALLER_FILENAME)).append(", "); sqlBuilder.append(dbNameResolver.getColumnName(ColumnName.CALLER_CLASS)).append(", "); sqlBuilder.append(dbNameResolver.getColumnName(ColumnName.CALLER_METHOD)).append(", "); sqlBuilder.append(dbNameResolver.getColumnName(ColumnName.CALLER_LINE)).append(") "); sqlBuilder.append("VALUES (?, ?, ? ,?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"); return sqlBuilder.toString(); } }复制代码

日志拦截  新建LogbackMarkerFilter类

import ch.qos.logback.classic.spi.ILoggingEvent;import ch.qos.logback.core.filter.AbstractMatcherFilter;import ch.qos.logback.core.spi.FilterReply;import org.slf4j.Marker;import org.slf4j.MarkerFactory; /** * @Title: LogbackMarkerFilter.java * @Description: TODO(日志拦截) * @Author: 爱飘de小子  上午10:15 */public class LogbackMarkerFilter extends AbstractMatcherFilter
{ private Marker markerToMatch = null; @Override public void start() { if (null != this.markerToMatch) { super.start(); } else { addError(" no MARKER yet !"); } } @Override public FilterReply decide(ILoggingEvent event) { Marker marker = event.getMarker(); if (!isStarted()) { return FilterReply.NEUTRAL; } if (null == marker) { return onMismatch; } if (markerToMatch.contains(marker)) { return onMatch; } return onMismatch; } public void setMarker(String markerStr) { if (null != markerStr) { markerToMatch = MarkerFactory.getMarker(markerStr); } } }复制代码

数据库脚本:

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;复制代码

主要用到logging_event表,logging_event_property和logging_event_exception可以删除。

使用:

//指定配置的Marker log.info(MarkerFactory.getMarker("DB"),"hello,logback!");复制代码

数据库显示如下

如果项目集成spring-data-jpa,可以不运行数据库脚本,配置开启自动更新表,并新建LoggingEvent类:

import lombok.Data;import javax.persistence.*; /** * @Title: LoggingEvent.java * @Description: TODO(日志持久实体) * @Author: 爱飘de小子  上午10:57 */@Data@Entity@Table(name="logging_event")public class LoggingEvent {     @Id    @GeneratedValue(strategy = GenerationType.IDENTITY)    @Basic(optional = false)    @Column(name = "event_id", nullable = false, columnDefinition = "BIGINT UNSIGNED")    private Long eventId;     @Column(name = "timestmp", nullable = false, columnDefinition = "BIGINT")    private Long timestmp;     @Column(name = "formatted_message", nullable = false, columnDefinition = "text")    private String formattedMessage;     @Column(name = "logger_name", nullable = false, columnDefinition = "varchar(254)")    private String loggerName;     @Column(name = "level_string", nullable = false, columnDefinition = "varchar(254)")    private String levelString;     @Column(name = "thread_name", columnDefinition = "varchar(254) DEFAULT NULL")    private String threadName;     @Column(name = "reference_flag", columnDefinition = "smallint(6)")    private Integer referenceFlag;     @Column(name = "arg0", columnDefinition = "varchar(254) DEFAULT NULL")    private String arg0;     @Column(name = "arg1", columnDefinition = "varchar(254) DEFAULT NULL")    private String arg1;     @Column(name = "arg2", columnDefinition = "varchar(254) DEFAULT NULL")    private String arg2;     @Column(name = "arg3", columnDefinition = "varchar(254) DEFAULT NULL")    private String arg3;     @Column(name = "caller_filename", nullable = false, columnDefinition = "varchar(254)")    private String callerFilename;     @Column(name = "caller_class", nullable = false, columnDefinition = "varchar(254)")    private String callerClass;     @Column(name = "caller_method", nullable = false, columnDefinition = "varchar(254)")    private String callerMethod;     @Column(name = "caller_line", nullable = false, columnDefinition = "varchar(5)")    private String callerLine; }复制代码

转载地址:http://fptta.baihongyu.com/

你可能感兴趣的文章
@RequestMapping 用法详解之地址映射
查看>>
254页PPT!这是一份写给NLP研究者的编程指南
查看>>
《Data Warehouse in Action》
查看>>
String 源码浅析(一)
查看>>
Spring Boot 最佳实践(三)模板引擎FreeMarker集成
查看>>
Fescar 发布 0.2.3 版本,支持 Redis 和 Apollo
查看>>
Google MapReduce到底解决什么问题?
查看>>
CCNP-6 OSPF试验2(BSCI)
查看>>
Excel 2013 全新的图表体验
查看>>
openstack 制作大于2TB根分区自动扩容的CENTOS镜像
查看>>
Unbuntu安装遭遇 vmware上的Easy install模式
查看>>
几个常用的ASP木马
查看>>
python分析postfix邮件日志的状态
查看>>
Mysql-5.6.x多实例配置
查看>>
psutil
查看>>
在git@osc上托管自己的代码
查看>>
机器学习算法:朴素贝叶斯
查看>>
小五思科技术学习笔记之扩展访问列表
查看>>
使用Python脚本检验文件系统数据完整性
查看>>
使用MDT部署Windows Server 2003 R2
查看>>