springboot oracle 日志输出到数据库
2020-07-11 本文已影响0人
爱吃菜的流浪狗
1.配置logback.xml文件
在logback文件下,配置数据源
mysql 5.0.7 版本以上支持
<appender name="DB" class="ch.qos.logback.classic.db.DBAppender">
<connectionSource class="ch.qos.logback.core.db.DriverManagerConnectionSource">
<driverClass>com.mysql.cj.jdbc.Driver</driverClass>
<url>*******i</url>
<user>***</user>
<password>****</password>
</connectionSource>
</appender>
oralce 14版本以上支持
<appender name="DB" class="ch.qos.logback.classic.db.DBAppender">
<connectionSource class="ch.qos.logback.core.db.DriverManagerConnectionSource">
<driverClass>oracle.jdbc.OracleDriver</driverClass>
<user>******</user>
<password>********</password>
<url>*******</url>
</connectionSource>
</appender>
带数据库连接池版本
连接池版本 com.alibaba:druid-spring-boot-starter:1.1.10
<appender name="DB" class="ch.qos.logback.classic.db.DBAppender">
<connectionSource class="ch.qos.logback.core.db.DataSourceConnectionSource">
<dataSource class="com.alibaba.druid.pool.DruidDataSource">
<driverClassName>oracle.jdbc.OracleDriver</driverClassName>
<username>*******</username>
<password>*******</password>
<url>*******</url>
</dataSource>
</connectionSource>
</appender>
2.重写 logback 写入DBAppender方法
重写的DBAppender方法
/**
* The DBAppender inserts logging events into three database tables in a format
* independent of the Java programming language.
*
* For more information about this appender, please refer to the online manual
* at http://logback.qos.ch/manual/appenders.html#DBAppender
*
* @author Ceki Gülcü
* @author Ray DeCampo
* @author Sébastien Pennec
*/
public class LogAppender extends DBAppenderBase<ILoggingEvent> {
protected String insertPropertiesSQL;
protected String insertExceptionSQL;
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();
insertExceptionSQL = buildInsertExceptionSQL(dbNameResolver);
insertPropertiesSQL = buildInsertPropertiesSQL(dbNameResolver);
insertSQL = buildInsertSQL(dbNameResolver);
super.start();
}
static String buildInsertPropertiesSQL(DBNameResolver dbNameResolver) {
StringBuilder sqlBuilder = new StringBuilder("INSERT INTO ");
sqlBuilder.append(dbNameResolver.getTableName(TableName.LOGGING_EVENT_PROPERTY)).append(" (");
sqlBuilder.append(dbNameResolver.getColumnName(ColumnName.EVENT_ID)).append(", ");
sqlBuilder.append(dbNameResolver.getColumnName(ColumnName.MAPPED_KEY)).append(", ");
sqlBuilder.append(dbNameResolver.getColumnName(ColumnName.MAPPED_VALUE)).append(") ");
sqlBuilder.append("VALUES (?, ?, ?)");
return sqlBuilder.toString();
}
static String buildInsertExceptionSQL(DBNameResolver dbNameResolver) {
StringBuilder sqlBuilder = new StringBuilder("INSERT INTO ");
sqlBuilder.append(dbNameResolver.getTableName(TableName.LOGGING_EVENT_EXCEPTION)).append(" (");
sqlBuilder.append(dbNameResolver.getColumnName(ColumnName.EVENT_ID)).append(", ");
sqlBuilder.append(dbNameResolver.getColumnName(ColumnName.I)).append(", ");
sqlBuilder.append(dbNameResolver.getColumnName(ColumnName.TRACE_LINE)).append(") ");
sqlBuilder.append("VALUES (?, ?, ?)");
return sqlBuilder.toString();
}
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();
}
@Override
protected void subAppend(ILoggingEvent event, Connection connection,
PreparedStatement insertStatement) throws Throwable {
Integer logSwitch = (Integer) Constant.getCacheMap().get("logSwitch");
if (logSwitch != null && logSwitch != 0) {
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");
}
}
}
protected void secondarySubAppend(ILoggingEvent event, Connection connection,
long eventId) throws Throwable {
Map<String, String> 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<String, String> mergePropertyMaps(ILoggingEvent event) {
Map<String, String> mergedMap = new HashMap<String, String>();
// 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<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;
}
@Override
protected Method getGeneratedKeysMethod() {
return GET_GENERATED_KEYS_METHOD;
}
@Override
protected String getInsertSQL() {
return insertSQL;
}
protected void insertProperties(Map<String, String> mergedMap,
Connection connection, long eventId) throws SQLException {
Set<String> propertiesKeys = mergedMap.keySet();
if (propertiesKeys.size() > 0) {
PreparedStatement insertPropertiesStatement = null;
try {
insertPropertiesStatement = connection
.prepareStatement(insertPropertiesSQL);
for (String key : propertiesKeys) {
String value = mergedMap.get(key);
insertPropertiesStatement.setLong(1, eventId);
insertPropertiesStatement.setString(2, key);
insertPropertiesStatement.setString(3, value);
if (cnxSupportsBatchUpdates) {
insertPropertiesStatement.addBatch();
} else {
insertPropertiesStatement.execute();
}
}
if (cnxSupportsBatchUpdates) {
insertPropertiesStatement.executeBatch();
}
} finally {
closeStatement(insertPropertiesStatement);
}
}
}
/**
* Add an exception statement either as a batch or execute immediately if
* batch updates are not supported.
*/
void updateExceptionStatement(PreparedStatement exceptionStatement,
String txt, short i, long eventId) throws SQLException {
exceptionStatement.setLong(1, eventId);
exceptionStatement.setShort(2, i);
exceptionStatement.setString(3, txt);
if (cnxSupportsBatchUpdates) {
exceptionStatement.addBatch();
} else {
exceptionStatement.execute();
}
}
short buildExceptionStatement(IThrowableProxy tp, short baseIndex,
PreparedStatement insertExceptionStatement, long eventId)
throws SQLException {
StringBuilder buf = new StringBuilder();
ThrowableProxyUtil.subjoinFirstLine(buf, tp);
updateExceptionStatement(insertExceptionStatement, buf.toString(),
baseIndex++, eventId);
int commonFrames = tp.getCommonFrames();
StackTraceElementProxy[] stepArray = tp.getStackTraceElementProxyArray();
for (int i = 0; i < stepArray.length - commonFrames; i++) {
StringBuilder sb = new StringBuilder();
sb.append(CoreConstants.TAB);
ThrowableProxyUtil.subjoinSTEP(sb, stepArray[i]);
updateExceptionStatement(insertExceptionStatement, sb.toString(),
baseIndex++, eventId);
}
if (commonFrames > 0) {
StringBuilder sb = new StringBuilder();
sb.append(CoreConstants.TAB).append("... ").append(commonFrames).append(
" common frames omitted");
updateExceptionStatement(insertExceptionStatement, sb.toString(),
baseIndex++, eventId);
}
return baseIndex;
}
protected void insertThrowable(IThrowableProxy tp, Connection connection,
long eventId) throws SQLException {
PreparedStatement exceptionStatement = null;
try {
exceptionStatement = connection.prepareStatement(insertExceptionSQL);
short baseIndex = 0;
while (tp != null) {
baseIndex = buildExceptionStatement(tp, baseIndex, exceptionStatement,
eventId);
tp = tp.getCause();
}
if (cnxSupportsBatchUpdates) {
exceptionStatement.executeBatch();
}
} finally {
closeStatement(exceptionStatement);
}
}
}
在数据库创建连接表
在logback.classic jar包中ch.qos.logback.classic.db.script下找对应的文件sql文件
否则容易出现触发器出发不了的问题
image.png
oralce数据库中创建表sql
SET FOREIGN_KEY_CHECKS=0;
-- ----------------------------
-- Table structure for logging_event
-- ----------------------------
DROP TABLE IF EXISTS `logging_event`;
CREATE TABLE `logging_event` (
`timestmp` bigint(20) NOT NULL,
`formatted_message` text NOT NULL,
`logger_name` varchar(254) NOT NULL,
`level_string` varchar(254) NOT NULL,
`thread_name` varchar(254) DEFAULT NULL,
`reference_flag` smallint(6) DEFAULT NULL,
`arg0` varchar(254) DEFAULT NULL,
`arg1` varchar(254) DEFAULT NULL,
`arg2` varchar(254) DEFAULT NULL,
`arg3` varchar(254) DEFAULT NULL,
`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(20) NOT NULL AUTO_INCREMENT,
PRIMARY KEY (`event_id`)
) ENGINE=InnoDB AUTO_INCREMENT=5245 DEFAULT CHARSET=latin1;
>SET FOREIGN_KEY_CHECKS=0;
-- ----------------------------
-- Table structure for logging_event_exception
-- ----------------------------
DROP TABLE IF EXISTS `logging_event_exception`;
CREATE TABLE `logging_event_exception` (
`event_id` bigint(20) NOT NULL,
`i` smallint(6) NOT NULL,
`trace_line` varchar(254) NOT NULL,
PRIMARY KEY (`event_id`,`i`),
CONSTRAINT `logging_event_exception_ibfk_1` FOREIGN KEY (`event_id`) REFERENCES `logging_event` (`event_id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
>SET FOREIGN_KEY_CHECKS=0;
-- ----------------------------
-- Table structure for logging_event_property
-- ----------------------------
DROP TABLE IF EXISTS `logging_event_property`;
CREATE TABLE `logging_event_property` (
`event_id` bigint(20) NOT NULL,
`mapped_key` varchar(254) NOT NULL,
`mapped_value` text,
PRIMARY KEY (`event_id`,`mapped_key`),
CONSTRAINT `logging_event_property_ibfk_1` FOREIGN KEY (`event_id`) REFERENCES `logging_event` (`event_id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
3.根据自己内容修改DBAppender方法
1) 修改插入语句
在DBappender中 ,通过获取XML配置中的connection链接
数组库字段映射.png
拼接sql
image.png
可对应修改插入字段,自定义数据库表
2)修改插入方法
image.png