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