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记录功能。

相关推荐
编码浪子7 分钟前
构建一个rust生产应用读书笔记7-确认邮件2
开发语言·后端·rust
Ch.yang9 分钟前
【Spring】 Bean 注入 HttpServletRequest 能保证线程安全的原理
java·spring·代理模式
web1508509664110 分钟前
基于Mysql、JavaScript、PHP、ajax开发的MBTI性格测试网站(前端+后端)
java
向上的车轮15 分钟前
云边端架构的优势是什么?面临哪些挑战?
架构·云边端
昙鱼18 分钟前
springboot创建web项目
java·前端·spring boot·后端·spring·maven
eternal__day18 分钟前
数据结构(哈希表(中)纯概念版)
java·数据结构·算法·哈希算法·推荐算法
FHYAAAX21 分钟前
灾备方案和架构类型、跨区域
架构·华为云
天之涯上上23 分钟前
JAVA开发 在 Spring Boot 中集成 Swagger
java·开发语言·spring boot
2402_8575834924 分钟前
“协同过滤技术实战”:网上书城系统的设计与实现
java·开发语言·vue.js·科技·mfc
白宇横流学长25 分钟前
基于SpringBoot的停车场管理系统设计与实现【源码+文档+部署讲解】
java·spring boot·后端