fly coding 監控(一):封裝基礎監控工廠,並實現日志監控

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

此前,本框架已有一套監控日志體系。此前,為提升數據庫與產品性能,我將日志文件分散存在本地文件中,在實際應用使用中,覺著不太合理,頻繁操作本地文件也會造成磁盤IO損耗,而且並沒有提升多高性能。

在一番思索後,我決定還是將所有的日志數據,均存儲在數據庫中,不過為了避免與業務庫性能交疊問題,我決定在此基礎上進行優化一下業務,可支持使用者獨立配置監控日志數據庫。

開發思路

為解決監控性能問題,我將使用線程池進行記錄。為解決多個功能之前重復代碼問題,我準備封裝一個“基礎監控工廠類”,將共用業務進行封裝,並提供抽象函數,由子類實現。

此系列將實現“日志”、“賬號”、“api”、“功能”、“sql”監控功能,此次將同步實現“日志”功能監控。

基礎功能開發

1. 監控工廠

package com.flycoding.monitor.factory.base;
import com.flycoding.drivenlibrary.engine.config.DrivenEngineConfig;
import com.flycoding.drivenlibrary.engine.config.constants.DrivenConstants;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
/**
 * 監控工廠類
 *
 * @author 趙屈犇
 * @version 1.0
 * @date 創建時間: 2020/10/5 15:26
 */
public class MonitorFactory {
    /**
     * 監聽工廠類
     */
    private static MonitorFactory factory;
    /**
     * 多線程執行服務
     */
    private ExecutorService executorService;
    public static MonitorFactory getInstance() {
        if (factory == null) {
            synchronized (MonitorFactory.class) {
                if (factory == null) {
                    factory = new MonitorFactory();
                }
            }
        }
        return factory;
    }
    protected MonitorFactory() {
        Integer corePoolSize = DrivenEngineConfig.getConfigValue(DrivenConstants.MonitorConstants.ThreadPoolConstants.CORE_POOL_SIZE, 10);
        Integer maxPoolSize = DrivenEngineConfig.getConfigValue(DrivenConstants.MonitorConstants.ThreadPoolConstants.MAX_POOL_SIZE, 10);
        Long keepAliveTime = DrivenEngineConfig.getConfigValue(DrivenConstants.MonitorConstants.ThreadPoolConstants.KEEP_ALIVE_TIME, 0L);
        executorService = new ThreadPoolExecutor(corePoolSize, maxPoolSize, keepAliveTime, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>());
    }
    /**
     * 獲取執行service
     *
     * @return
     */
    public ExecutorService getExecutorService() {
        return executorService;
    }
}

此功能,用於定義監控工廠的線程池,其中核心線程池大小、最大線程池大小、最大等待時間支持用戶yml配置,框架內置默認值。

2. 基礎監控工廠

package com.flycoding.monitor.factory.base;
import com.flycoding.biz.account.factory.UserFactory;
import com.flycoding.dblibrary.executor.inter.ISqlExecutor;
import com.flycoding.drivenlibrary.context.RequestContextHolder;
import com.flycoding.drivenlibrary.database.executor.MonitorSqlExecutor;
import com.flycoding.drivenlibrary.engine.config.DrivenEngineConfig;
import com.flycoding.drivenlibrary.engine.config.constants.DrivenConstants;
import com.flycoding.drivenlibrary.engine.util.RequestUtils;
import com.flycoding.monitor.entity.MonitorLoggerPO;
import com.flycoding.monitor.entity.base.BaseMonitorPO;
import com.flycoding.monitor.entity.base.BaseRequestMonitorPO;
import com.flycoding.monitor.factory.MonitorFileFactory;
import com.flycoding.utillibrary.date.TimeUtils;
import com.flycoding.utillibrary.java.ThrowableUtil;
import com.flycoding.utillibrary.logger.LoggerFactory;
import com.flycoding.utillibrary.strings.StringUtils;
import javax.servlet.http.HttpServletRequest;
import java.sql.SQLSyntaxErrorException;
/**
 * 基礎監控工廠類
 *
 * @author 趙屈犇
 * @version 1.0
 * @date 創建時間: 2021/5/28 下午10:07
 */
public abstract class BaseMonitorFactory<T extends BaseMonitorFactory> {
    /**
     * 記錄開始時間
     */
    protected long startTime;
    /**
     * 錯誤異常
     */
    protected Throwable throwable;
    /**
     * 是否開啟監控   用戶代理信息   請求客戶端信息  異常信息  輸出控制臺 輸出db
     */
    protected boolean isMonitor, isUserAgent, isRequestClient, isThrowable, isOutputConsole, isOutputDatabase;
    /**
     * 配置前綴   獲取瀏覽器信息    獲取客戶端信息    獲取IP地址   賬號ID  渠道編碼  應用渠道編碼
     */
    protected String prefix, userAgent, requestClient, ipAddress, accountId, channelCode, appChannelCode;
    protected BaseMonitorFactory() {
        prefix = StringUtils.appendStrings(DrivenConstants.MonitorConstants.PREFIX, getMonitorConfigKey(), ".");
        isMonitor = DrivenEngineConfig.getConfigValue(prefix   DrivenConstants.MonitorConstants.IS_MONITOR, true);
        isUserAgent = DrivenEngineConfig.getConfigValue(prefix   DrivenConstants.MonitorConstants.IS_SAVE_USER_AGENT, true);
        isRequestClient = DrivenEngineConfig.getConfigValue(prefix   DrivenConstants.MonitorConstants.IS_SAVE_REQUEST_CLIENT, true);
        isThrowable = DrivenEngineConfig.getConfigValue(prefix   DrivenConstants.MonitorConstants.IS_SAVE_THROWABLE, true);
        isOutputConsole = DrivenEngineConfig.getConfigValue(prefix   DrivenConstants.MonitorConstants.IS_OUTPUT_CONSOLE, true);
        isOutputDatabase = DrivenEngineConfig.getConfigValue(prefix   DrivenConstants.MonitorConstants.IS_OUTPUT_DATABASE, true);
        init();
        initServletRequest(RequestContextHolder.getServletRequest());
    }
    public T init() {
        startTime = System.currentTimeMillis();
        throwable(null);
        return (T) this;
    }
    /**
     * 設置啟動時間
     *
     * @param startTime
     * @return
     */
    public T startTime(long startTime) {
        this.startTime = startTime;
        return (T) this;
    }
    /**
     * 初始化請求數據
     *
     * @param request
     * @return
     */
    private void initServletRequest(HttpServletRequest request) {
        if (isMonitor) {
            if (request != null) {
                try {
                    setChannelCode(RequestContextHolder.getChannelCode());
                    setAppChannelCode(RequestContextHolder.getAppChannelCode());
                    if (isGetAccountId()) {
                        // 獲取當前用戶ID
                        this.accountId = UserFactory.builder().setChannelCode(getMonitorChannelCode()).getAccountId();
                    }
                    if (isUserAgent) {
                        // 獲取瀏覽器信息
                        this.userAgent = request.getHeader("user-agent");
                    }
                    if (isRequestClient) {
                        // 獲取客戶端信息
                        this.requestClient = RequestUtils.getRequestContent(request);
                    }
                    // 獲取IP地址
                    this.ipAddress = RequestUtils.getIPAddress(request);
                } catch (Exception e) {
                }
            }
        }
    }
    /**
     * 設置是否監控
     *
     * @param monitor
     * @return
     */
    public T monitor(boolean monitor) {
        isMonitor = monitor;
        return (T) this;
    }
    /**
     * 設置異常
     *
     * @param throwable
     * @return
     */
    public T throwable(Throwable throwable) {
        if (isMonitor && isThrowable) {
            this.throwable = throwable;
        }
        return (T) this;
    }
    /**
     * 設置賬號id
     *
     * @param accountId
     * @return
     */
    public T accountId(String accountId) {
        if (isMonitor) {
            this.accountId = accountId;
        }
        return (T) this;
    }
    /**
     * 獲取執行時長
     *
     * @return
     */
    protected long getDuration() {
        return TimeUtils.getNowTimeMills() - startTime;
    }
    /**
     * 設置渠道編碼
     *
     * @param channelCode
     */
    public void setChannelCode(String channelCode) {
        if (isMonitor) {
            this.channelCode = channelCode;
        }
    }
    /**
     * 設置應用渠道編碼
     *
     * @param appChannelCode
     */
    public void setAppChannelCode(String appChannelCode) {
        if (isMonitor) {
            this.appChannelCode = appChannelCode;
        }
    }
    /**
     * 記錄監控
     *
     * @return
     */
    public T record() {
        if (isMonitor) {
            long duration = getDuration();
            MonitorFactory.getInstance().getExecutorService().submit(() -> {
                // 日志工廠類
                LoggerFactory logger = LoggerFactory.getLogger(getClass().getName());
                try {
                    // 監控文件工廠
                    MonitorFileFactory monitorFileFactory = MonitorFileFactory.getInstance();
                    // 獲取監控信息
                    BaseMonitorPO monitorInfo = getMonitorInfo(duration, monitorFileFactory);
                    if (monitorInfo != null) {
                        // 執行器
                        ISqlExecutor executor = MonitorSqlExecutor.newInstance().setRecordSQL(false);
                        if (monitorInfo instanceof MonitorLoggerPO) {
                            executor.setRecordLog(false);
                        }
                        if (monitorInfo instanceof BaseRequestMonitorPO) {
                            BaseRequestMonitorPO requestMonitorPO = (BaseRequestMonitorPO) monitorInfo;
                            // 存儲異常信息
                            if (isThrowable) {
                                requestMonitorPO.setThrowable(ThrowableUtil.throwableConvertString(throwable));
                            }
                            // 存儲用戶代理信息
                            if (isUserAgent) {
                                requestMonitorPO.setUserAgent(userAgent);
                            }
                            // 存儲客戶端請求內容
                            if (isRequestClient) {
                                requestMonitorPO.setRequestClient(requestClient);
                            }
                            requestMonitorPO.setIpAddress(ipAddress);
                        }
                        monitorInfo.setAccountId(accountId);
                        monitorInfo.setChannelCode(channelCode);
                        monitorInfo.setAppChannelCode(appChannelCode);
                        monitorInfo.save(executor);
                    }
                } catch (SQLSyntaxErrorException e) {
                } catch (Exception e) {
                    logger.error("記錄監控信息失敗", e);
                }
            });
        }
        return (T) this;
    }
    /**
     * 獲取監控信息
     *
     * @param duration
     * @param monitorFileFactory
     * @return
     * @throws Exception
     */
    protected abstract BaseMonitorPO getMonitorInfo(long duration, MonitorFileFactory monitorFileFactory) throws Exception;
    /**
     * 獲取監控配置
     *
     * @return
     */
    protected abstract String getMonitorConfigKey();
    /**
     * 獲取監控渠道編碼
     *
     * @return
     */
    protected abstract String getMonitorChannelCode();
    /**
     * 是否獲取賬號id
     *
     * @return
     */
    protected boolean isGetAccountId() {
        return true;
    }
}

此功能實現基礎監控工廠類,封裝基礎監控功能。

此類定義了是否“開啟監控,記錄用戶代理信息 、請求客戶端信息、異常信息、輸出控制臺、輸出db” yml配置並配置默認值。

封裝了初始化請求數據。記錄調用函數,此函數已實現通過“線程池”動態創建,並其中封裝了一些常用記錄參數功能。

3. 監控SQL執行器

package com.flycoding.drivenlibrary.database.executor;
import com.flycoding.drivenlibrary.database.executor.impl.AbstractSqlExecutor;
import com.flycoding.drivenlibrary.engine.config.DrivenEngineConfig;
/**
 * 監控sql執行器
 *
 * @author 趙屈犇
 * @version 1.0
 * @date 創建時間: 2023/12/21 20:37
 * @Copyright(C): 2023 by 趙屈犇
 */
public class MonitorSqlExecutor extends AbstractSqlExecutor {
    public static MonitorSqlExecutor newInstance() {
        return new MonitorSqlExecutor();
    }
    public MonitorSqlExecutor() {
    }
    @Override
    protected String getDBConfigValue() {
        return DrivenEngineConfig.getInstance().getMonitorDBConfigPath();
    }
    @Override
    protected String getTemplateFolder() {
        return "monitor";
    }
}

定義監控數據庫執行器,此配置若未配置監控配置時,將采用默認後臺數據庫配置。若配置,則采用監控配置。

4. 配置監控模型

/**
 * 監控模型數據編碼
 */
@ModelDBConfig(dbConfigName = "系統監控模型配置", extendPackageNames = {"com.flycoding.monitor"},
    dataExecutorClass = MonitorSqlExecutor.class, dbConfigFileName = DrivenConfigConstants.MONITOR_MODEL_DB_NAME,
    createDBPackageNames = {"com.flycoding.monitor.entity"}, dictionarys = {}, apiModuleUrl = "driven")
String MONITOR_MODEL = "MONITOR_MODEL";	

日志監控功能開發

此上,業已實現監控基礎配置。此下,將具體實現日志監控功能。我將從數據庫設計-日志工廠實現-效果演示逐步該功能。

1. 設計數據庫

2. 定義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;
import com.flycoding.drivenlibrary.engine.constants.DefaultFieldConstants;
import com.flycoding.drivenlibrary.engine.constants.FieldConfigConstants;
import com.flycoding.drivenlibrary.engine.constants.config.DrivenElementConstants;
import com.flycoding.drivenlibrary.enums.dictionary.QueryType;
import com.flycoding.monitor.entity.base.BaseMonitorPO;
import com.flycoding.utillibrary.logger.LoggerLevel;
/**
 * 日志監控對象
 *
 * @author 趙屈犇
 * @version 1.0
 * @date 創建時間: 2018/2/6 下午11:14
 */
@Table(tableName = MonitorLoggerPO.TABLE_NAME)
@FunctionConfig(funcName = "日志管理", funcCode = "Sy_Monitor_Logger", tableConfig = @TableConfig(tableName = MonitorLoggerPO.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 MonitorLoggerPO extends BaseMonitorPO {
    public static final String TABLE_NAME = "Sys_Monitor_Logger";
    @PrimaryAuto(columnName = "id", comment = "日志ID")
    @FormFieldConfig(fieldCode = "id", fieldName = "日志ID", isPageVisibility = false, isTableEnable = false, fieldParentName = MONITOR_BASIC_MESSAGE_NAME)
    private Integer id;
    /**
     * 日志標簽
     */
    @Column(columnName = "logger_tag", length = 200, isNotNull = true, comment = "日志標簽")
    @FormFieldConfig(fieldCode = "logger_tag", fieldName = "日志標簽", isVerifyEmpty = true, tableQueryType = QueryType.LIKE, fieldParentName = MONITOR_BASIC_MESSAGE_NAME, tableColumnWidth = "235")
    private String loggerTag;
    /**
     * 日志級別
     */
    @FormFieldConfig(fieldCode = "logger_level", fieldName = "日志級別", tableQueryType = QueryType.EQUAL, elementCode = DrivenElementConstants.SELECT_ELEMENT, fieldParentName = MONITOR_BASIC_MESSAGE_NAME,
            dict = @DictConfig(dictCode = ConfigDictionaryConstants.LoggerLevelConstants.DICTIONARY_CODE))
    @Column(columnName = "logger_level", length = 6, isNotNull = true, comment = "日志級別")
    private String loggerLevel;
    /**
     * 關聯主鍵ID
     */
    @Column(columnName = "relevance_id", columnType = ColumnType.VARCHAR, length = 34)
    private String relevanceId;
    /**
     * 日志內容
     */
    @Column(columnName = "logger_content", columnType = ColumnType.LONG_TEXT, comment = "日志內容")
    @FormFieldConfig(fieldCode = "logger_content", fieldName = "日志內容", config = @FieldConfig(appendCss = FieldConfigConstants.CSS_HALF_SCREEN_COL),
            elementCode = DrivenElementConstants.BIG_INPUT_ELEMENT, isTableEnable = false, fieldParentName = BaseMonitorPO.DETAIL_BASIC_MESSAGE_NAME)
    private String loggerContent;
    /**
     * 日志級別
     */
    private LoggerLevel level;
    /**
     * 是否輸出錯誤
     */
    private boolean isOutToError;
    public Integer getId() {
        return id;
    }
    public void setId(Integer id) {
        this.id = id;
    }
    public String getLoggerTag() {
        return loggerTag;
    }
    public void setLoggerTag(String loggerTag) {
        this.loggerTag = loggerTag;
    }
    public String getLoggerLevel() {
        return loggerLevel;
    }
    public void setLoggerLevel(String loggerLevel) {
        this.loggerLevel = loggerLevel;
    }
    public String getRelevanceId() {
        return relevanceId;
    }
    public void setRelevanceId(String relevanceId) {
        this.relevanceId = relevanceId;
    }
    public LoggerLevel getLevel() {
        return level;
    }
    public void setLevel(LoggerLevel level) {
        this.level = level;
    }
    public boolean isOutToError() {
        return isOutToError;
    }
    public void setOutToError(boolean outToError) {
        isOutToError = outToError;
    }
    public String getLoggerContent() {
        return loggerContent;
    }
    public void setLoggerContent(String loggerContent) {
        this.loggerContent = loggerContent;
    }
}

3. 實現日志監控工廠

package com.flycoding.monitor.factory;
import com.flycoding.biz.manage.constants.ManageDictionaryConstants;
import com.flycoding.monitor.entity.MonitorLoggerPO;
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.utillibrary.date.TimeUtils;
import com.flycoding.utillibrary.date.enums.DateStyle;
import com.flycoding.utillibrary.java.ThrowableUtil;
import com.flycoding.utillibrary.logger.LoggerConfig;
import com.flycoding.utillibrary.logger.LoggerLevel;
import com.flycoding.utillibrary.strings.StringUtils;
/**
 * 日志監控工廠類
 *
 * @author 趙屈犇
 * @version 1.0
 * @date 創建時間: 2020/10/8 20:43
 */
public class MonitorLoggerFactory extends BaseMonitorFactory<MonitorLoggerFactory> {
    /**
     * 日志級別
     */
    private LoggerLevel level;
    /**
     * 日志別名   日志信息  關聯主鍵
     */
    private String logTag, message, relevanceId;
    /**
     * 是否輸出錯誤   是否記錄日志
     */
    private boolean isOutToError, isSaveLogger;
    public static MonitorLoggerFactory builder() {
        return new MonitorLoggerFactory();
    }
    private MonitorLoggerFactory() {
        super();
        isSaveLogger = DrivenEngineConfig.getConfigValue(prefix   DrivenConstants.MonitorConstants.IS_SAVE_LOGGER, true);
    }
    /**
     * 日志別名
     *
     * @param logTag
     * @return
     */
    public MonitorLoggerFactory logTag(String logTag) {
        this.logTag = logTag;
        return this;
    }
    /**
     * 日志信息
     *
     * @param message
     * @return
     */
    public MonitorLoggerFactory message(String message) {
        this.message = message;
        return this;
    }
    /**
     * 日志級別
     *
     * @param level
     * @return
     */
    public MonitorLoggerFactory level(LoggerLevel level) {
        this.level = level;
        return this;
    }
    /**
     * 是否輸出錯誤,控制臺錯誤警告
     *
     * @param outToError
     * @return
     */
    public MonitorLoggerFactory outToError(boolean outToError) {
        isOutToError = outToError;
        return this;
    }
    /**
     * 關聯主鍵
     *
     * @param relevanceId
     * @return
     */
    public MonitorLoggerFactory relevanceId(String relevanceId) {
        this.relevanceId = relevanceId;
        return this;
    }
    @Override
    protected BaseMonitorPO getMonitorInfo(long duration, MonitorFileFactory monitorFileFactory) throws Exception {
        MonitorLoggerPO monitorInfo = new MonitorLoggerPO();
        monitorInfo.setLevel(level);
        monitorInfo.setLoggerTag(logTag);
        monitorInfo.setOutToError(isOutToError);
        monitorInfo.setRelevanceId(relevanceId);
        monitorInfo.setLoggerLevel(level.getTag());
        // 日志配置
        LoggerConfig loggerConfig = LoggerConfig.getInstance();
        // 生成日志信息
        StringBuffer loggerContent = new StringBuffer(TimeUtils.getNowTimeString(DateStyle.YYYY_MM_DD_HH_MM_SS_SSS.getValue()));
        loggerContent.append(" ").append(level.getTag()).append("/").append(logTag).append(": ").append(message);
        // 異常轉換字符串
        String throwableMessage = ThrowableUtil.throwableConvertString(throwable);
        if (StringUtils.isNotEmpty(throwableMessage)) {
            loggerContent.append("\n").append(throwableMessage);
        }
        // 判斷控制臺日志級別
        if (level.getLevelValue() >= loggerConfig.getConsoleLoggerLevel().getLevelValue()) {
            /**
             * 輸出日志到控制臺
             */
            if (isOutputConsole) {
                if (isOutToError) {
                    System.err.println(loggerContent);
                } else {
                    System.out.println(loggerContent);
                }
            }
        }
        // 判斷數據庫日志級別
        if (level.getLevelValue() >= loggerConfig.getDataBaseLoggerLevel().getLevelValue()) {
            /**
             * 輸出日志到DB文件中
             */
            if (isOutputDatabase) {
                // 存儲異常信息
                if (isSaveLogger) {
                    monitorInfo.setLoggerContent(loggerContent.toString());
                }
                return monitorInfo;
            } else {
                return null;
            }
        } else {
            return null;
        }
    }
    @Override
    protected String getMonitorConfigKey() {
        return "logger";
    }
    @Override
    protected String getMonitorChannelCode() {
        return ManageDictionaryConstants.ChannelDictionary.MONITOR_LOGGER;
    }
}

此工廠,實現了日志監控工廠將日志記錄數據庫中。

4. 實現日志工廠

package com.flycoding.utillibrary.logger;
import com.flycoding.monitor.factory.MonitorLoggerFactory;
/**
 * 日志工廠類
 *
 * @author 趙屈犇
 * @version 1.0
 * @date 創建時間: 2018/2/6 下午11:16
 */
public class LoggerFactory {
    /**
     * 日志標簽
     */
    private String tag;
    /**
     * 關聯業務主鍵ID
     */
    private String relevanceId;
    /**
     * 是否記錄日志
     */
    private boolean isRecordLog = true;
    public static LoggerFactory getLogger() {
        return getLogger("");
    }
    public static LoggerFactory getLogger(String tag) {
        return new LoggerFactory(tag);
    }
    private LoggerFactory() {
    }
    private LoggerFactory(String tag) {
        this.tag = tag;
    }
    /**
     * 設置TAG
     *
     * @param tag
     */
    public LoggerFactory setTag(String tag) {
        this.tag = tag;
        return this;
    }
    /**
     * 設置關聯主鍵ID
     *
     * @param relevanceId
     * @return
     */
    public LoggerFactory setRelevanceId(String relevanceId) {
        this.relevanceId = relevanceId;
        return this;
    }
    /**
     * =============非靜態輸出日志=============
     */
    public LoggerFactory debug(String message) {
        debug(message, null);
        return this;
    }
    public LoggerFactory info(String message) {
        info(message, null);
        return this;
    }
    public LoggerFactory warn(String message) {
        warn(message, null);
        return this;
    }
    public LoggerFactory error(String message) {
        error(message, null);
        return this;
    }
    /**
     * =============非靜態輸出日志=============
     */
    /**
     * =============非靜態輸出異常信息=============
     */
    public LoggerFactory debug(Throwable throwable) {
        debug("", throwable);
        return this;
    }
    public LoggerFactory info(Throwable throwable) {
        info("", throwable);
        return this;
    }
    public LoggerFactory warn(Throwable throwable) {
        warn("", throwable);
        return this;
    }
    public LoggerFactory error(Throwable throwable) {
        error("", throwable);
        return this;
    }
    /**
     * =============非靜態輸出異常信息=============
     */
    /**
     * =============非靜態輸出異常信息=============
     */
    public LoggerFactory debug(String message, Throwable throwable) {
        printLog(LoggerLevel.DEBUG, tag, message, throwable, false);
        return this;
    }
    public LoggerFactory info(String message, Throwable throwable) {
        printLog(LoggerLevel.INFO, tag, message, throwable, false);
        return this;
    }
    public LoggerFactory warn(String message, Throwable throwable) {
        printLog(LoggerLevel.WARN, tag, message, throwable, false);
        return this;
    }
    public LoggerFactory error(String message, Throwable throwable) {
        printLog(LoggerLevel.ERROR, tag, message, throwable, true);
        return this;
    }
    /**
     * =============非靜態輸出異常信息=============
     */
    /**
     * 設置是否記錄日志
     *
     * @param recordLog
     * @return a
     * @author 趙屈犇
     * @date 創建時間: 2022/6/18 21:31
     * @version 1.0
     */
    public void setRecordLog(boolean recordLog) {
        isRecordLog = recordLog;
    }
    /**
     * 打印輸出日志
     *
     * @param level
     * @param tag
     * @param message
     * @param throwable
     * @param isOutToErr
     */
    private void printLog(LoggerLevel level, String tag, String message, Throwable throwable, boolean isOutToErr) {
        if (isRecordLog) {
            MonitorLoggerFactory.builder().level(level).logTag(tag).message(message).throwable(throwable).outToError(isOutToErr)
                    .relevanceId(relevanceId).record();
        }
    }
}

至此,日志工廠類已實現。