fly coding 监控(二):实现SQL监控

此前,已改造完基础监控工厂。此篇,将基于此前的功能,实现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记录功能。

相关推荐
Barcke几秒前
深入浅出 Spring WebFlux:从核心原理到深度实战
后端
JuiceFS1 分钟前
从 MLPerf Storage v2.0 看 AI 训练中的存储性能与扩展能力
运维·后端
大鸡腿同学3 分钟前
Think with a farmer's mindset
后端
Moonbit24 分钟前
用MoonBit开发一个C编译器
后端·编程语言·编译器
Reboot1 小时前
达梦数据库GROUP BY报错解决方法
后端
稻草人22221 小时前
java Excel 导出 ,如何实现八倍效率优化,以及代码分层,方法封装
后端·架构
渣哥1 小时前
原来 Java 里线程安全集合有这么多种
java
间彧1 小时前
Spring Boot集成Spring Security完整指南
java
掘金者阿豪1 小时前
打通KingbaseES与MyBatis:一篇详尽的Java数据持久化实践指南
前端·后端
间彧2 小时前
Spring Secutiy基本原理及工作流程
java