fly coding 监控(一):封装基础监控工厂,并实现日志监控

70 阅读8分钟

此前,本框架已有一套监控日志体系。此前,为提升数据库与产品性能,我将日志文件分散存在本地文件中,在实际应用使用中,觉着不太合理,频繁操作本地文件也会造成磁盘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();
        }
    }
}

至此,日志工厂类已实现。