Logback根据Marker是否插入自定义数据库日志信息

一、重写DBAppender

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
import ch.qos.logback.classic.Level;
import ch.qos.logback.classic.db.DBAppender;
import ch.qos.logback.classic.spi.ILoggingEvent;
import dm.jdbc.util.ReflectUtil;
import org.springframework.stereotype.Component;

import javax.persistence.Column;
import javax.persistence.Table;
import java.lang.reflect.Field;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.Map;


@Component
public class DiyDBAppender extends DBAppender {

private ILoggingEvent iLoggingEvent;

Map<String, String> mergePropertyMaps(ILoggingEvent event) {
Map<String, String> mergedMap = new HashMap();
Map<String, String> loggerContextMap = event.getLoggerContextVO().getPropertyMap();
Map<String, String> mdcMap = event.getMDCPropertyMap();
if (loggerContextMap != null) {
mergedMap.putAll(loggerContextMap);
}

if (mdcMap != null) {
mergedMap.putAll(mdcMap);
}

return mergedMap;
}

protected void secondarySubAppend(ILoggingEvent event, Connection connection, long eventId) throws Throwable {
Map mergedMap = mergePropertyMaps(event);
iLoggingEvent = event;
System.out.println("进入自定义日志插入");

// 此处根据log第一个参数判断是否自定义插入日志
// 改用Marker判断后废弃
//if ("InsertLog".equals(iLoggingEvent.getArgumentArray()[0])) {}

// 在这里传入自定义的数据库连接,实现切换数据库日志插入
// 从数据库连接池获取connection

// 插入数据库
insertOwnerLog(event, "传入上方的数据库链接", eventId);
}

private void insertOwnerLog(ILoggingEvent event, Connection connection, long eventId) throws Exception {
Object[] params = event.getArgumentArray();
Object param = params[1];
Class<?> aClass = param.getClass();
// 表名
StringBuffer tableNameStr = new StringBuffer("insert into ");
// 字段字符串
StringBuffer fieldStr = new StringBuffer("(");
// 值字符串
StringBuffer valueStr = new StringBuffer("values (");
DruidConfiguration druidConfiguration = new DruidConfiguration();

// 查看是否有@Table注解
Table table = aClass.getAnnotation(Table.class);
if (table == null) {
return;
} else {
// 拼接表名
tableNameStr.append(table.name() + " ");
}

// 获取所有属性
Field[] declaredFields = aClass.getDeclaredFields();

for (int i = 0, size = declaredFields.length; i < size; i++) {
Column columnAnnot = declaredFields[i].getAnnotation(Column.class);
if (declaredFields[i].getAnnotation(Column.class) != null) {
// 获取属性的@Column的值 拼接字段名
String columnName = columnAnnot.name();
fieldStr.append(columnName);
if (i == size - 1) {
fieldStr.append(") ");
} else {
fieldStr.append(",");
}

// 获取字段值
Object fieldValue = ReflectUtil.getFieldValue(param, declaredFields[i].getName());
if (fieldValue instanceof String) {
valueStr.append("\"" + fieldValue + "\"");
} else {
valueStr.append(fieldValue);
}

if (i == size - 1) {
valueStr.append(")");
} else {
valueStr.append(",");
}
}
}

// 拼接插入sql语句
tableNameStr.append(fieldStr).append(valueStr);

Level level = event.getLevel();
PreparedStatement insertStatement = null;

// 执行数据库插入
try {
insertStatement = connection.prepareStatement(tableNameStr.toString());
if (insertStatement != null) {
insertStatement.execute();
}
} catch (Exception e) {
e.printStackTrace();
} finally {
//closeStatement(insertStatement);
}
}

private DiyDBAppender setLong(PreparedStatement statement, int parameterIndex, Long value) throws SQLException {
statement.setLong(parameterIndex, value);
return this;

}

private DiyDBAppender setInt(PreparedStatement statement, int parameterIndex, Integer value) throws SQLException {
// 默认操作类型为others
statement.setInt(parameterIndex, value != null ? value : 5);
return this;
}

private DiyDBAppender setString(PreparedStatement statement, int parameterIndex, String value) throws SQLException {
statement.setString(parameterIndex, value);
return this;
}

}

注意:需要配合Mybatis生成的实体类使用。

二、xml配置文件(部分)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<appender name="CUSTOM_DB" class="com.pansoft.xbrl.ccdc.service.DiyDBAppender">
<!-- 过滤器 -->
<filter class="ch.qos.logback.core.filter.EvaluatorFilter">
<evaluator
class="ch.qos.logback.classic.boolex.JaninoEventEvaluator">
<!-- 过滤Maker -->
<expression>return (marker != null &amp;&amp; "test".equals(marker.getName()));</expression>
</evaluator>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
<connectionSource class="ch.qos.logback.core.db.DataSourceConnectionSource">
<dataSource class="com.alibaba.druid.pool.DruidDataSource">
<username>数据库用户名</username>
<password>数据库密码</password>
<driverClassName>数据库驱动</driverClassName>
<url>数据库链接</url>
</dataSource>
</connectionSource>
</appender>

这里是相关的配置文件,使用了Druid的数据库连接池。

标题“一”中的获取数据库链接是根据程序运行过程中切换数据库实现的方式。这里必须配置默认的链接,否则会造成启动报错。

三、测试

1
2
3
4
// 创建Marker对象
public static final Marker MARKER = MarkerFactory.getMarker("test");
// 使用Marker进行过滤
logger.info(MARKER, "{}", "hhhh");