fly coding 監控(二):實現SQL監控

2024年2月6日 22点热度 0人点赞

此前,已改造完基礎監控工廠。此篇,將基於此前的功能,實現SQL語句的監控日志記錄。

開發思路

為實現對系統執行SQL進行監控,主要記錄“執行時長”、“轉換類”、“是否執行成功”、“執行器”、“執行Sql腳本”、“執行參數”、“返回結果”等數據。在後期系統上線運行過程中,進行實時監控,便於優化產品性能。

設計數據庫

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定義

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;
    }
}

監控工廠實現

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記錄功能。