此前,已改造完基础监控工厂。此篇,将基于此前的功能,实现SQL语句的监控日志记录。
开发思路
为实现对系统执行SQL进行监控,主要记录"执行时长"、"转换类"、"是否执行成功"、"执行器"、"执行Sql脚本"、"执行参数"、"返回结果"等数据。在后期系统上线运行过程中,进行实时监控,便于优化产品性能。
设计数据库
yml配置
yml
# sql监控配置
sql:
# 是否监控
is-monitor: true
# 是否输出到控制台
is-output-console: true
# 是否保存用户代理信息
is-save-user-agent: true
# 是否保存异常信息
is-save-throwable: true
# 是否保存请求客户端信息
is-save-request-client: true
# 是否保存sql语句
is-save-sql: true
# 是否保存返回结果集
is-save-return-results: true
# 是否保存执行参数
is-save-execute-params: true
此上配置参数,用于动态配置是否开启指定记录项。
PO定义
java
package com.flycoding.monitor.entity;
import com.flycoding.dblibrary.annotation.create.Column;
import com.flycoding.dblibrary.annotation.create.PrimaryAuto;
import com.flycoding.dblibrary.annotation.create.Table;
import com.flycoding.dblibrary.enums.ColumnType;
import com.flycoding.dblibrary.enums.OrderByType;
import com.flycoding.drivenlibrary.engine.annotation.function.FunctionConfig;
import com.flycoding.drivenlibrary.engine.annotation.function.config.popup.PopupConfig;
import com.flycoding.drivenlibrary.engine.annotation.function.config.table.TableConfig;
import com.flycoding.drivenlibrary.engine.annotation.function.form.FormConfig;
import com.flycoding.drivenlibrary.engine.annotation.function.form.FormFieldConfig;
import com.flycoding.drivenlibrary.engine.annotation.function.form.field.DictConfig;
import com.flycoding.drivenlibrary.engine.annotation.function.form.field.FieldConfig;
import com.flycoding.drivenlibrary.engine.config.constants.dictionary.ConfigDictionaryConstants.EnableCodeDictionary;
import com.flycoding.drivenlibrary.engine.constants.DefaultFieldConstants;
import com.flycoding.drivenlibrary.engine.constants.FieldConfigConstants;
import com.flycoding.drivenlibrary.engine.constants.SqlConstants;
import com.flycoding.drivenlibrary.engine.constants.config.DrivenElementConstants;
import com.flycoding.monitor.entity.base.BaseMonitorPO;
import com.flycoding.monitor.entity.base.BaseRequestMonitorPO;
/**
* 监控SQL语句
*
* @author 赵屈犇
* @version 1.0
* @date 创建时间: 2020/10/8 20:35
*/
@Table(tableName = MonitorSqlPO.TABLE_NAME)
@FunctionConfig(funcName = "SQL执行监控", funcCode = "Sy_Monitor_Sql", tableConfig = @TableConfig(tableName = MonitorSqlPO.TABLE_NAME,
columns = {
@Column(columnName = DefaultFieldConstants.CREATE_TIME, isInsertUse = false, isSelectUse = false, orderBy = OrderByType.DESC)
}), formConfig = @FormConfig(keyCode = "id", isCreateTableAddBtn = false, popupConfig = @PopupConfig(popupWidth = 850, popupHeight = 550)))
public class MonitorSqlPO extends BaseRequestMonitorPO {
public static final String TABLE_NAME = "Sys_Monitor_Sql";
@PrimaryAuto(columnName = "id", comment = "主键ID")
@FormFieldConfig(fieldCode = "id", fieldName = "SqlID", isPageVisibility = false, isTableEnable = false, fieldParentName = MONITOR_BASIC_MESSAGE_NAME)
private Integer id;
/**
* 转换类别名
*/
@FormFieldConfig(fieldCode = "convert_class_name", fieldName = "转换类别名", fieldParentName = MONITOR_BASIC_MESSAGE_NAME)
@Column(columnName = "convert_class_name", columnType = ColumnType.VARCHAR, length = SqlConstants.DB_NAME_SIZE)
private String convertClassName;
/**
* 执行时长
*/
@FormFieldConfig(fieldCode = "executor_duration", fieldName = "执行时长(毫秒)", fieldParentName = MONITOR_BASIC_MESSAGE_NAME)
@Column(columnName = "executor_duration", columnType = ColumnType.INTEGER, length = 20)
private Long executorDuration;
/**
* 执行是否成功
*/
@FormFieldConfig(fieldCode = "is_executor_success", fieldName = "是否执行成功", elementCode = DrivenElementConstants.RADIO_ELEMENT,
pageDefaultValue = EnableCodeDictionary.YES, fieldParentName = MONITOR_BASIC_MESSAGE_NAME,
dict = @DictConfig(dictCode = EnableCodeDictionary.DICTIONARY_CODE))
@Column(columnName = "is_executor_success", columnType = ColumnType.VARCHAR, length = SqlConstants.DICTIONARY_VALUE_SIZE)
private String isExecutorSuccess;
/**
* 数据库执行器包名
*/
@FormFieldConfig(fieldCode = "executor_class_name", fieldName = "执行器名称", fieldParentName = MONITOR_BASIC_MESSAGE_NAME)
@Column(columnName = "executor_class_name", columnType = ColumnType.VARCHAR, length = SqlConstants.DB_NAME_SIZE)
private String executorClassName;
/**
* 执行Sql语句
*/
@Column(columnName = "execute_sql", columnType = ColumnType.LONG_TEXT, comment = "执行SQL")
@FormFieldConfig(fieldCode = "execute_sql", fieldName = "执行SQL", config = @FieldConfig(appendCss = FieldConfigConstants.CSS_HALF_SCREEN_COL),
elementCode = DrivenElementConstants.BIG_INPUT_ELEMENT, isTableEnable = false, fieldParentName = BaseMonitorPO.DETAIL_BASIC_MESSAGE_NAME)
private String executeSql;
/**
* 执行参数
*/
@Column(columnName = "execute_params", columnType = ColumnType.LONG_TEXT, comment = "执行参数")
@FormFieldConfig(fieldCode = "execute_params", fieldName = "执行参数", config = @FieldConfig(appendCss = FieldConfigConstants.CSS_HALF_SCREEN_COL),
elementCode = DrivenElementConstants.BIG_INPUT_ELEMENT, isTableEnable = false, fieldParentName = BaseMonitorPO.DETAIL_BASIC_MESSAGE_NAME)
private String executeParams;
/**
* 返回结果
*/
@Column(columnName = "return_results", columnType = ColumnType.LONG_TEXT, comment = "返回结果")
@FormFieldConfig(fieldCode = "return_results", fieldName = "返回结果", config = @FieldConfig(appendCss = FieldConfigConstants.CSS_HALF_SCREEN_COL),
elementCode = DrivenElementConstants.BIG_INPUT_ELEMENT, isTableEnable = false, fieldParentName = BaseMonitorPO.DETAIL_BASIC_MESSAGE_NAME)
private String returnResults;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getConvertClassName() {
return convertClassName;
}
public void setConvertClassName(String convertClassName) {
this.convertClassName = convertClassName;
}
public Long getExecutorDuration() {
return executorDuration;
}
public void setExecutorDuration(Long executorDuration) {
this.executorDuration = executorDuration;
}
public String getIsExecutorSuccess() {
return isExecutorSuccess;
}
public void setIsExecutorSuccess(String isExecutorSuccess) {
this.isExecutorSuccess = isExecutorSuccess;
}
public String getExecutorClassName() {
return executorClassName;
}
public void setExecutorClassName(String executorClassName) {
this.executorClassName = executorClassName;
}
public String getExecuteSql() {
return executeSql;
}
public void setExecuteSql(String executeSql) {
this.executeSql = executeSql;
}
public String getExecuteParams() {
return executeParams;
}
public void setExecuteParams(String executeParams) {
this.executeParams = executeParams;
}
public String getReturnResults() {
return returnResults;
}
public void setReturnResults(String returnResults) {
this.returnResults = returnResults;
}
}
监控工厂实现
java
package com.flycoding.monitor.factory;
import com.flycoding.biz.manage.constants.ManageDictionaryConstants;
import com.flycoding.monitor.entity.MonitorSqlPO;
import com.flycoding.monitor.entity.base.BaseMonitorPO;
import com.flycoding.monitor.factory.base.BaseMonitorFactory;
import com.flycoding.drivenlibrary.engine.config.DrivenEngineConfig;
import com.flycoding.drivenlibrary.engine.config.constants.DrivenConstants;
import com.flycoding.drivenlibrary.engine.config.factory.ClassAliasFactory;
import com.flycoding.utillibrary.BasicUtils;
import com.flycoding.utillibrary.date.TimeUtils;
import com.flycoding.utillibrary.date.enums.DateStyle;
import com.flycoding.utillibrary.java.JSONUtils;
import com.flycoding.utillibrary.java.ThrowableUtil;
import com.flycoding.utillibrary.strings.StringUtils;
/**
* 监控SQL的工厂类
*
* @author 赵屈犇
* @version 1.0
* @date 创建时间: 2020/10/8 20:50
*/
public class MonitorSqlFactory extends BaseMonitorFactory<MonitorSqlFactory> {
/**
* 查询结果
*/
private Object results;
/**
* 请求参数
*/
private Object[] params;
/**
* 是否执行成功
*/
private boolean isSuccess;
/**
* 转换的class
*/
private Class convertClass;
/**
* 执行sql 执行器扩展类
*/
private String sql, executorClassName;
/**
* 执行结果集 sql 执行参数
*/
private boolean isReturnResults, isSaveSql, isExecuteParams;
public static MonitorSqlFactory builder() {
return new MonitorSqlFactory();
}
private MonitorSqlFactory() {
super();
isSaveSql = DrivenEngineConfig.getConfigValue(prefix + DrivenConstants.MonitorConstants.IS_SAVE_SQL, true);
isReturnResults = DrivenEngineConfig.getConfigValue(prefix + DrivenConstants.MonitorConstants.IS_SAVE_RETURN_RESULTS, true);
isExecuteParams = DrivenEngineConfig.getConfigValue(prefix + DrivenConstants.MonitorConstants.IS_SAVE_EXECUTE_PARAMS, true);
}
/**
* sql语句
*
* @param sql
* @return
*/
public MonitorSqlFactory sql(String sql) {
if (isMonitor && isSaveSql) {
this.sql = sql;
}
return this;
}
/**
* 执行结果
*
* @param results
* @return
*/
public MonitorSqlFactory results(Object results) {
if (isMonitor && isReturnResults) {
this.results = results;
}
return this;
}
/**
* 请求参数
*
* @param params
* @return
*/
public MonitorSqlFactory params(Object[] params) {
if (isMonitor && isExecuteParams) {
this.params = params;
}
return this;
}
/**
* 是否执行成功
*
* @param isSuccess
* @return
*/
public MonitorSqlFactory success(boolean isSuccess) {
this.isSuccess = isSuccess;
return this;
}
/**
* 转换class类
*
* @param convertClass
* @return
*/
public MonitorSqlFactory convertClass(Class convertClass) {
this.convertClass = convertClass;
return this;
}
/**
* 执行器class
*
* @param executorClassName
* @return
*/
public MonitorSqlFactory executorClassName(String executorClassName) {
this.executorClassName = executorClassName;
return this;
}
@Override
protected BaseMonitorPO getMonitorInfo(long duration, MonitorFileFactory monitorFileFactory) throws Exception {
MonitorSqlPO monitorInfo = new MonitorSqlPO();
// 执行器类全名
if (StringUtils.isNotEmpty(executorClassName)) {
monitorInfo.setExecutorClassName(executorClassName);
}
// 是否执行成功
monitorInfo.setIsExecutorSuccess(BasicUtils.getEnableCode(isSuccess));
// 转换类
monitorInfo.setConvertClassName(ClassAliasFactory.getClassName(convertClass));
// 存储sql语句
if (isSaveSql) {
monitorInfo.setExecuteSql(sql);
}
// 存储请求参数
if (isExecuteParams) {
monitorInfo.setExecuteParams(JSONUtils.toJSON(params));
}
// 存储返回结果
if (isReturnResults) {
monitorInfo.setReturnResults(JSONUtils.toJSON(results));
}
if (isOutputConsole) {
StringBuffer content = new StringBuffer("====================").append(TimeUtils.getNowTimeString(DateStyle.YYYY_MM_DD_HH_MM_SS_SSS.getValue()))
.append("===============").append("\nSQL语句:\n")
.append(sql).append("\n执行参数:\n").append(JSONUtils.toJSON(params))
.append("\n执行结果:\n").append(JSONUtils.toJSON(results));
if (throwable != null) {
content.append("\n错误信息:\n").append(ThrowableUtil.throwableConvertString(throwable));
}
content.append("\n==========================执行时长:").append(duration).append("==========================");
if (isSuccess) {
System.out.println(content);
} else {
System.err.println(content);
}
}
// 设置执行时长
monitorInfo.setExecutorDuration(duration);
return monitorInfo;
}
@Override
protected String getMonitorConfigKey() {
return "sql";
}
@Override
protected String getMonitorChannelCode() {
return ManageDictionaryConstants.ChannelDictionary.MONITOR_SQL;
}
}
此工厂,实现了sql记录功能。