mirror of https://gitee.com/stylefeng/roses
【7.6.0】【框架改造】删掉文件存储的业务日志
parent
674502dfdf
commit
d12ac2be31
|
@ -57,7 +57,6 @@
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>javax.servlet</groupId>
|
<groupId>javax.servlet</groupId>
|
||||||
<artifactId>javax.servlet-api</artifactId>
|
<artifactId>javax.servlet-api</artifactId>
|
||||||
<optional>true</optional>
|
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
|
@ -1,54 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright [2020-2030] [https://www.stylefeng.cn]
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*
|
|
||||||
* Guns采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
|
|
||||||
*
|
|
||||||
* 1.请不要删除和修改根目录下的LICENSE文件。
|
|
||||||
* 2.请不要删除和修改Guns源码头部的版权声明。
|
|
||||||
* 3.请保留源码和相关描述文件的项目出处,作者声明等。
|
|
||||||
* 4.分发源码时候,请注明软件出处 https://gitee.com/stylefeng/guns
|
|
||||||
* 5.在修改包名,模块名称,项目代码等时,请注明软件出处 https://gitee.com/stylefeng/guns
|
|
||||||
* 6.若您的项目无法满足以上几点,可申请商业授权
|
|
||||||
*/
|
|
||||||
package cn.stylefeng.roses.kernel.log.api.enums;
|
|
||||||
|
|
||||||
import lombok.Getter;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 日志存储的方式,数据库还是文件
|
|
||||||
*
|
|
||||||
* @author fengshuonan
|
|
||||||
* @since 2020/12/24 14:08
|
|
||||||
*/
|
|
||||||
@Getter
|
|
||||||
public enum LogSaveTypeEnum {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 存储到数据库
|
|
||||||
*/
|
|
||||||
DB("db"),
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 存储到文件
|
|
||||||
*/
|
|
||||||
FILE("file");
|
|
||||||
|
|
||||||
LogSaveTypeEnum(String code) {
|
|
||||||
this.code = code;
|
|
||||||
}
|
|
||||||
|
|
||||||
private final String code;
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,48 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright [2020-2030] [https://www.stylefeng.cn]
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*
|
|
||||||
* Guns采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
|
|
||||||
*
|
|
||||||
* 1.请不要删除和修改根目录下的LICENSE文件。
|
|
||||||
* 2.请不要删除和修改Guns源码头部的版权声明。
|
|
||||||
* 3.请保留源码和相关描述文件的项目出处,作者声明等。
|
|
||||||
* 4.分发源码时候,请注明软件出处 https://gitee.com/stylefeng/guns
|
|
||||||
* 5.在修改包名,模块名称,项目代码等时,请注明软件出处 https://gitee.com/stylefeng/guns
|
|
||||||
* 6.若您的项目无法满足以上几点,可申请商业授权
|
|
||||||
*/
|
|
||||||
package cn.stylefeng.roses.kernel.log.api.pojo.log;
|
|
||||||
|
|
||||||
import lombok.Data;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 日志配置信息
|
|
||||||
*
|
|
||||||
* @author liuhanqing
|
|
||||||
* @since 2020-12-20 13:53
|
|
||||||
**/
|
|
||||||
@Data
|
|
||||||
public class SysLogProperties {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 日志存储类型:db-数据库,file-文件,默认存储在数据库中
|
|
||||||
*/
|
|
||||||
private String type = "db";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* file存储类型日志文件的存储位置
|
|
||||||
*/
|
|
||||||
private String fileSavePath = "_sys_log";
|
|
||||||
|
|
||||||
}
|
|
|
@ -1 +0,0 @@
|
||||||
日志记录的sdk,用于将日志记录到文件中,提供相关日志管理接口
|
|
|
@ -1,45 +0,0 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
|
||||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
|
||||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
|
||||||
<modelVersion>4.0.0</modelVersion>
|
|
||||||
|
|
||||||
<parent>
|
|
||||||
<groupId>cn.stylefeng.roses</groupId>
|
|
||||||
<artifactId>kernel-d-log</artifactId>
|
|
||||||
<version>7.6.0</version>
|
|
||||||
<relativePath>../pom.xml</relativePath>
|
|
||||||
</parent>
|
|
||||||
|
|
||||||
<artifactId>log-sdk-file</artifactId>
|
|
||||||
|
|
||||||
<packaging>jar</packaging>
|
|
||||||
|
|
||||||
<dependencies>
|
|
||||||
|
|
||||||
<!--日志模块的api-->
|
|
||||||
<dependency>
|
|
||||||
<groupId>cn.stylefeng.roses</groupId>
|
|
||||||
<artifactId>log-api</artifactId>
|
|
||||||
<version>${roses.version}</version>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
|
|
||||||
<!--登陆模块的api-->
|
|
||||||
<dependency>
|
|
||||||
<groupId>cn.stylefeng.roses</groupId>
|
|
||||||
<artifactId>auth-api</artifactId>
|
|
||||||
<version>${roses.version}</version>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<!--config模块的api-->
|
|
||||||
<!--用来配置一些参数,例如日志的存放路径等-->
|
|
||||||
<dependency>
|
|
||||||
<groupId>cn.stylefeng.roses</groupId>
|
|
||||||
<artifactId>config-api</artifactId>
|
|
||||||
<version>${roses.version}</version>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
</dependencies>
|
|
||||||
|
|
||||||
</project>
|
|
|
@ -1,388 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright [2020-2030] [https://www.stylefeng.cn]
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*
|
|
||||||
* Guns采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
|
|
||||||
*
|
|
||||||
* 1.请不要删除和修改根目录下的LICENSE文件。
|
|
||||||
* 2.请不要删除和修改Guns源码头部的版权声明。
|
|
||||||
* 3.请保留源码和相关描述文件的项目出处,作者声明等。
|
|
||||||
* 4.分发源码时候,请注明软件出处 https://gitee.com/stylefeng/guns
|
|
||||||
* 5.在修改包名,模块名称,项目代码等时,请注明软件出处 https://gitee.com/stylefeng/guns
|
|
||||||
* 6.若您的项目无法满足以上几点,可申请商业授权
|
|
||||||
*/
|
|
||||||
package cn.stylefeng.roses.kernel.log.file;
|
|
||||||
|
|
||||||
import cn.hutool.core.date.DateUtil;
|
|
||||||
import cn.hutool.core.io.FileUtil;
|
|
||||||
import cn.hutool.core.lang.Dict;
|
|
||||||
import cn.hutool.core.util.ObjectUtil;
|
|
||||||
import cn.stylefeng.roses.kernel.auth.api.context.LoginContext;
|
|
||||||
import cn.stylefeng.roses.kernel.db.api.pojo.page.PageResult;
|
|
||||||
import cn.stylefeng.roses.kernel.log.api.LogManagerApi;
|
|
||||||
import cn.stylefeng.roses.kernel.log.api.exception.LogException;
|
|
||||||
import cn.stylefeng.roses.kernel.log.api.exception.enums.LogExceptionEnum;
|
|
||||||
import cn.stylefeng.roses.kernel.log.api.pojo.manage.LogManagerRequest;
|
|
||||||
import cn.stylefeng.roses.kernel.log.api.pojo.record.LogRecordDTO;
|
|
||||||
import com.alibaba.fastjson.JSON;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
|
|
||||||
import java.io.*;
|
|
||||||
import java.text.ParseException;
|
|
||||||
import java.text.SimpleDateFormat;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Calendar;
|
|
||||||
import java.util.Date;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import static cn.stylefeng.roses.kernel.log.api.constants.LogConstants.DEFAULT_BEGIN_PAGE_NO;
|
|
||||||
import static cn.stylefeng.roses.kernel.log.api.constants.LogConstants.DEFAULT_PAGE_SIZE;
|
|
||||||
import static cn.stylefeng.roses.kernel.log.api.constants.LogFileConstants.FILE_CONTRACT_SYMBOL;
|
|
||||||
import static cn.stylefeng.roses.kernel.log.api.constants.LogFileConstants.FILE_SUFFIX;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 文件日志读取管理实现类
|
|
||||||
*
|
|
||||||
* @author majianguo
|
|
||||||
* @since 2020/11/3 上午10:56
|
|
||||||
*/
|
|
||||||
@Slf4j
|
|
||||||
public class FileLogManagerServiceImpl implements LogManagerApi {
|
|
||||||
|
|
||||||
private final String fileSavePath;
|
|
||||||
|
|
||||||
private Integer total;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 构造函数
|
|
||||||
*
|
|
||||||
* @param fileSavePath 文件保存路径
|
|
||||||
*/
|
|
||||||
public FileLogManagerServiceImpl(String fileSavePath) {
|
|
||||||
this.fileSavePath = fileSavePath;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public List<LogRecordDTO> findList(LogManagerRequest logManagerParam) {
|
|
||||||
PageResult<LogRecordDTO> pageResult = findPage(logManagerParam);
|
|
||||||
return pageResult.getRows();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public PageResult<LogRecordDTO> findPage(LogManagerRequest logManagerParam) {
|
|
||||||
|
|
||||||
// 文件日志,必须有AppName,否则文件太多太大
|
|
||||||
if (ObjectUtil.isEmpty(logManagerParam.getAppName())) {
|
|
||||||
throw new LogException(LogExceptionEnum.APP_NAME_NOT_EXIST);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 文件日志,必须有开始时间,否则文件太多太大
|
|
||||||
if (ObjectUtil.isEmpty(logManagerParam.getBeginDate())) {
|
|
||||||
throw new LogException(LogExceptionEnum.BEGIN_DATETIME_NOT_EXIST);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 获取文件路径
|
|
||||||
String filePath = getLogPath(logManagerParam.getAppName(), logManagerParam.getBeginDate());
|
|
||||||
|
|
||||||
// 文件当前指针
|
|
||||||
long filePointer = 0L;
|
|
||||||
if (logManagerParam.getPageNo() == null) {
|
|
||||||
logManagerParam.setPageNo(DEFAULT_BEGIN_PAGE_NO);
|
|
||||||
} else {
|
|
||||||
// 如果页数不等于1,则根据当前登陆用户信息取出上次读取文件的位置
|
|
||||||
if (!DEFAULT_BEGIN_PAGE_NO.equals(logManagerParam.getPageNo())) {
|
|
||||||
Object pointer = LoginContext.me().getLoginUser().getOtherInfos().get("filePointer");
|
|
||||||
if (ObjectUtil.isNotEmpty(pointer)) {
|
|
||||||
filePointer = (long) pointer;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (logManagerParam.getPageSize() == null) {
|
|
||||||
logManagerParam.setPageSize(DEFAULT_PAGE_SIZE);
|
|
||||||
}
|
|
||||||
// 返回分页结果
|
|
||||||
PageResult<LogRecordDTO> pageResult = new PageResult<>();
|
|
||||||
pageResult.setPageSize(logManagerParam.getPageSize());
|
|
||||||
|
|
||||||
// 读取日志
|
|
||||||
List<LogRecordDTO> dtos = readLog(filePath, filePointer, logManagerParam.getPageSize());
|
|
||||||
pageResult.setRows(dtos);
|
|
||||||
pageResult.setTotalRows(total);
|
|
||||||
return pageResult;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void del(LogManagerRequest logManagerParam) {
|
|
||||||
|
|
||||||
// 删除操作,必须有appName
|
|
||||||
if (ObjectUtil.isEmpty(logManagerParam.getAppName())) {
|
|
||||||
throw new LogException(LogExceptionEnum.APP_NAME_NOT_EXIST);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 删除操作,必须有appName
|
|
||||||
if (ObjectUtil.isEmpty(logManagerParam.getBeginDate())) {
|
|
||||||
throw new LogException(LogExceptionEnum.BEGIN_DATETIME_NOT_EXIST);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 文件日志,必须有结束时间,否则文件太多太大
|
|
||||||
if (ObjectUtil.isEmpty(logManagerParam.getEndDate())) {
|
|
||||||
throw new LogException(LogExceptionEnum.END_DATETIME_NOT_EXIST);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 计算开始和结束两个时间之间的所有日期
|
|
||||||
List<String> dates = getIntervalDate(logManagerParam.getBeginDate(), logManagerParam.getEndDate());
|
|
||||||
|
|
||||||
// 查找每一天的日志
|
|
||||||
for (String date : dates) {
|
|
||||||
|
|
||||||
// 拼接文件名称
|
|
||||||
String logPath = getLogPath(logManagerParam.getAppName(), date);
|
|
||||||
|
|
||||||
// 删除日志
|
|
||||||
if (FileUtil.exist(logPath)) {
|
|
||||||
FileUtil.del(logPath);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public LogRecordDTO detail(LogManagerRequest logManagerRequest) {
|
|
||||||
|
|
||||||
// 文件日志,必须有AppName,否则文件太多太大
|
|
||||||
if (ObjectUtil.isEmpty(logManagerRequest.getAppName())) {
|
|
||||||
throw new LogException(LogExceptionEnum.APP_NAME_NOT_EXIST);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 文件日志,必须有开始时间,否则文件太多太大
|
|
||||||
if (ObjectUtil.isEmpty(logManagerRequest.getBeginDate())) {
|
|
||||||
throw new LogException(LogExceptionEnum.BEGIN_DATETIME_NOT_EXIST);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 获取文件路径
|
|
||||||
String filePath = getLogPath(logManagerRequest.getAppName(), logManagerRequest.getBeginDate());
|
|
||||||
return this.readLog(filePath, logManagerRequest.getLogId());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 根据app名称和日期获取日志文件全路径
|
|
||||||
*
|
|
||||||
* @param appName APP名称
|
|
||||||
* @param date 那一天的日志
|
|
||||||
* @return 文件全路径名称
|
|
||||||
* @author majianguo
|
|
||||||
* @since 2020/11/3 下午4:29
|
|
||||||
*/
|
|
||||||
private String getLogPath(String appName, String date) {
|
|
||||||
|
|
||||||
// 根据传入的AppName和时间来定位确定一个唯一的文件名称
|
|
||||||
String fileName = appName + FILE_CONTRACT_SYMBOL + DateUtil.parse(date).toDateStr() + FILE_SUFFIX;
|
|
||||||
|
|
||||||
// 文件绝对路径生成,带文件名的完整路径
|
|
||||||
String fileAbsolutePath = fileSavePath + File.separator;
|
|
||||||
return fileAbsolutePath + fileName;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 根据id获取日志记录
|
|
||||||
*
|
|
||||||
* @author chenjinlong
|
|
||||||
* @since 2021/2/1 19:54
|
|
||||||
*/
|
|
||||||
private LogRecordDTO readLog(String path, Long logId) {
|
|
||||||
|
|
||||||
// 判断文件是否存在,不存在直接返回Null
|
|
||||||
if (!FileUtil.exist(path)) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
LogRecordDTO logRecordDTO = new LogRecordDTO();
|
|
||||||
RandomAccessFile file;
|
|
||||||
try {
|
|
||||||
// 创建随机读文件流
|
|
||||||
file = new RandomAccessFile(path, "r");
|
|
||||||
|
|
||||||
while (true) {
|
|
||||||
|
|
||||||
String str = file.readLine();
|
|
||||||
|
|
||||||
// 读取到的字符串不为空
|
|
||||||
if (ObjectUtil.isNotEmpty(str)) {
|
|
||||||
logRecordDTO = parseObject(str);
|
|
||||||
if (logRecordDTO.getLogId().equals(logId)) {
|
|
||||||
return logRecordDTO;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} catch (Exception e) {
|
|
||||||
if (log.isDebugEnabled()) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
log.error(e.getMessage());
|
|
||||||
}
|
|
||||||
return logRecordDTO;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 从指定的文件指针处,开始读取指定行数的数据
|
|
||||||
*
|
|
||||||
* @param path 文件全路径
|
|
||||||
* @param filePointer 开始读取文件指针位置
|
|
||||||
* @param lineNum 读取行数
|
|
||||||
* @author majianguo
|
|
||||||
* @since 2020/11/3 下午1:36
|
|
||||||
*/
|
|
||||||
private List<LogRecordDTO> readLog(String path, long filePointer, int lineNum) {
|
|
||||||
// 判断文件是否存在,不存在直接返回Null
|
|
||||||
if (!FileUtil.exist(path)) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 返回结果集
|
|
||||||
List<LogRecordDTO> readLines = new ArrayList<>();
|
|
||||||
|
|
||||||
RandomAccessFile file;
|
|
||||||
try {
|
|
||||||
// 创建随机读文件流
|
|
||||||
file = new RandomAccessFile(path, "r");
|
|
||||||
|
|
||||||
// 设置文件指针
|
|
||||||
file.seek(filePointer);
|
|
||||||
|
|
||||||
// 从设置的指针处开始读取文件
|
|
||||||
for (int i = 0; i < lineNum; ++i) {
|
|
||||||
String str = file.readLine();
|
|
||||||
|
|
||||||
// 读取到的字符串不为空
|
|
||||||
if (ObjectUtil.isNotEmpty(str)) {
|
|
||||||
LogRecordDTO recordDTO = parseObject(str);
|
|
||||||
|
|
||||||
// 格式转换没有问题就加入到列表中
|
|
||||||
if (ObjectUtil.isNotEmpty(recordDTO)) {
|
|
||||||
readLines.add(recordDTO);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//获取总行数
|
|
||||||
|
|
||||||
total = getTotalLines(new File(path));
|
|
||||||
|
|
||||||
// 在用户信息中记录当前用户读取的文件指针
|
|
||||||
LoginContext.me().getLoginUser().setOtherInfos(Dict.create().set("filePointer", file.getFilePointer()));
|
|
||||||
|
|
||||||
} catch (Exception e) {
|
|
||||||
if (log.isDebugEnabled()) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
log.error(e.getMessage());
|
|
||||||
}
|
|
||||||
return readLines;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 根据传入的JSON字符串转换成JAVA对象
|
|
||||||
*
|
|
||||||
* @param jsonStr json字符串
|
|
||||||
* @return 返回格式化后的Java对象 如果格式错误,则返回Null
|
|
||||||
* @author majianguo
|
|
||||||
* @since 2020/11/3 下午2:16
|
|
||||||
*/
|
|
||||||
private LogRecordDTO parseObject(String jsonStr) {
|
|
||||||
LogRecordDTO logRecordDTO = null;
|
|
||||||
try {
|
|
||||||
|
|
||||||
// 这里接受到的jsonStr是乱码的,需要通过getBytes方法转换成字节数组,然后通过newString的方式再转换回来
|
|
||||||
logRecordDTO = JSON.parseObject(new String(getBytes(jsonStr.toCharArray())), LogRecordDTO.class);
|
|
||||||
} catch (Exception e) {
|
|
||||||
if (log.isDebugEnabled()) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
log.error(e.getMessage());
|
|
||||||
}
|
|
||||||
return logRecordDTO;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 解决readLine读取中文乱码问题
|
|
||||||
*
|
|
||||||
* @param chars 乱码的字符串转数组
|
|
||||||
* @author majianguo
|
|
||||||
* @since 2020/11/3 下午4:03
|
|
||||||
*/
|
|
||||||
public static byte[] getBytes(char[] chars) {
|
|
||||||
byte[] result = new byte[chars.length];
|
|
||||||
for (int i = 0; i < chars.length; i++) {
|
|
||||||
result[i] = (byte) chars[i];
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 计算两个日期之间所有的日期
|
|
||||||
*
|
|
||||||
* @param start 开始日期 间隔
|
|
||||||
* @param end 结束日期
|
|
||||||
* @author majianguo
|
|
||||||
* @since 2020/11/3 下午4:23
|
|
||||||
*/
|
|
||||||
public static List<String> getIntervalDate(String start, String end) {
|
|
||||||
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
|
|
||||||
|
|
||||||
// 保存日期集合
|
|
||||||
List<String> list = new ArrayList<>();
|
|
||||||
try {
|
|
||||||
|
|
||||||
Date dateStart = sdf.parse(start);
|
|
||||||
Date dateEnd = sdf.parse(end);
|
|
||||||
Date date = dateStart;
|
|
||||||
|
|
||||||
// 用Calendar 进行日期比较判断
|
|
||||||
Calendar cd = Calendar.getInstance();
|
|
||||||
while (date.getTime() <= dateEnd.getTime()) {
|
|
||||||
list.add(sdf.format(date));
|
|
||||||
cd.setTime(date);
|
|
||||||
|
|
||||||
// 增加一天 放入集合
|
|
||||||
cd.add(Calendar.DATE, 1);
|
|
||||||
date = cd.getTime();
|
|
||||||
}
|
|
||||||
|
|
||||||
} catch (ParseException e) {
|
|
||||||
if (log.isDebugEnabled()) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
log.error(e.getMessage());
|
|
||||||
}
|
|
||||||
return list;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取总行数
|
|
||||||
*
|
|
||||||
* @param file 日志文件路径
|
|
||||||
* @return 日志总行数
|
|
||||||
* @author chenjinlong
|
|
||||||
* @since 2021/2/1 19:45
|
|
||||||
*/
|
|
||||||
public int getTotalLines(File file) throws IOException {
|
|
||||||
FileReader in = new FileReader(file);
|
|
||||||
LineNumberReader reader = new LineNumberReader(in);
|
|
||||||
reader.skip(Long.MAX_VALUE);
|
|
||||||
int lines = reader.getLineNumber();
|
|
||||||
reader.close();
|
|
||||||
return lines;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,351 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright [2020-2030] [https://www.stylefeng.cn]
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*
|
|
||||||
* Guns采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
|
|
||||||
*
|
|
||||||
* 1.请不要删除和修改根目录下的LICENSE文件。
|
|
||||||
* 2.请不要删除和修改Guns源码头部的版权声明。
|
|
||||||
* 3.请保留源码和相关描述文件的项目出处,作者声明等。
|
|
||||||
* 4.分发源码时候,请注明软件出处 https://gitee.com/stylefeng/guns
|
|
||||||
* 5.在修改包名,模块名称,项目代码等时,请注明软件出处 https://gitee.com/stylefeng/guns
|
|
||||||
* 6.若您的项目无法满足以上几点,可申请商业授权
|
|
||||||
*/
|
|
||||||
package cn.stylefeng.roses.kernel.log.file;
|
|
||||||
|
|
||||||
import cn.hutool.core.collection.CollectionUtil;
|
|
||||||
import cn.hutool.core.date.DateUtil;
|
|
||||||
import cn.hutool.core.io.FileUtil;
|
|
||||||
import cn.hutool.core.util.ObjectUtil;
|
|
||||||
import cn.hutool.core.util.StrUtil;
|
|
||||||
import cn.hutool.log.Log;
|
|
||||||
import cn.hutool.log.LogFactory;
|
|
||||||
import cn.stylefeng.roses.kernel.log.api.LogRecordApi;
|
|
||||||
import cn.stylefeng.roses.kernel.log.api.constants.LogFileConstants;
|
|
||||||
import cn.stylefeng.roses.kernel.log.api.pojo.record.LogRecordDTO;
|
|
||||||
import cn.stylefeng.roses.kernel.log.api.threadpool.LogManagerThreadPool;
|
|
||||||
import com.alibaba.fastjson.JSON;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.nio.charset.StandardCharsets;
|
|
||||||
import java.util.*;
|
|
||||||
import java.util.concurrent.ConcurrentLinkedQueue;
|
|
||||||
import java.util.concurrent.TimeUnit;
|
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
|
||||||
import java.util.concurrent.atomic.AtomicLong;
|
|
||||||
|
|
||||||
import static cn.stylefeng.roses.kernel.log.api.constants.LogFileConstants.FILE_CONTRACT_SYMBOL;
|
|
||||||
import static cn.stylefeng.roses.kernel.log.api.constants.LogFileConstants.FILE_SUFFIX;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 文件存储方式的日志记录器
|
|
||||||
*
|
|
||||||
* @author fengshuonan
|
|
||||||
* @since 2020/10/28 14:52
|
|
||||||
*/
|
|
||||||
public class FileLogRecordServiceImpl implements LogRecordApi {
|
|
||||||
|
|
||||||
private final LogManagerThreadPool logManagerThreadPool;
|
|
||||||
|
|
||||||
private final LogRefreshManager logRefreshManager;
|
|
||||||
|
|
||||||
private final String fileSavePath;
|
|
||||||
|
|
||||||
public FileLogRecordServiceImpl(String fileSavePath, LogManagerThreadPool logManagerThreadPool) {
|
|
||||||
this.fileSavePath = fileSavePath;
|
|
||||||
this.logManagerThreadPool = logManagerThreadPool;
|
|
||||||
this.logRefreshManager = new LogRefreshManager();
|
|
||||||
this.logRefreshManager.start();
|
|
||||||
}
|
|
||||||
|
|
||||||
public FileLogRecordServiceImpl(String fileSavePath, LogManagerThreadPool logManagerThreadPool, long sleepTime, int maxCount) {
|
|
||||||
this.fileSavePath = fileSavePath;
|
|
||||||
this.logManagerThreadPool = logManagerThreadPool;
|
|
||||||
this.logRefreshManager = new LogRefreshManager(sleepTime, maxCount);
|
|
||||||
this.logRefreshManager.start();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 日志文件的组成形式应为appName-年-月-日.log
|
|
||||||
*
|
|
||||||
* @author fengshuonan
|
|
||||||
* @since 2020/10/28 15:53
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public void add(LogRecordDTO logRecordDTO) {
|
|
||||||
|
|
||||||
if (logRecordDTO == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 输出日志
|
|
||||||
addBatch(CollectionUtil.list(false, logRecordDTO));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 批量输出日志
|
|
||||||
*
|
|
||||||
* @param list 待输出日志列表
|
|
||||||
* @author majianguo
|
|
||||||
* @since 2020/11/2 下午2:59
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public void addBatch(List<LogRecordDTO> list) {
|
|
||||||
|
|
||||||
if (ObjectUtil.isEmpty(list)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 获取appName
|
|
||||||
String appName = list.get(0).getAppName();
|
|
||||||
if (StrUtil.isBlank(appName)) {
|
|
||||||
appName = LogFileConstants.DEFAULT_LOG_FILE_NAME;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 获取日志记录的日期
|
|
||||||
Date dateTime = list.get(0).getDateTime();
|
|
||||||
if (dateTime == null) {
|
|
||||||
dateTime = new Date();
|
|
||||||
}
|
|
||||||
String dateStr = DateUtil.formatDate(dateTime);
|
|
||||||
|
|
||||||
// 拼接文件名
|
|
||||||
String fileName = appName + FILE_CONTRACT_SYMBOL + dateStr + FILE_SUFFIX;
|
|
||||||
|
|
||||||
// 文件绝对路径生成,带文件名的完整路径
|
|
||||||
String fileAbsolutePath = fileSavePath + File.separator + fileName;
|
|
||||||
|
|
||||||
// 判断文件是否存在,不存在则创建
|
|
||||||
boolean existFlag = FileUtil.exist(fileAbsolutePath);
|
|
||||||
if (!existFlag) {
|
|
||||||
FileUtil.touch(fileAbsolutePath);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 将对象转换成JSON输出
|
|
||||||
List<String> outList = new ArrayList<>();
|
|
||||||
for (LogRecordDTO recordDTO : list) {
|
|
||||||
outList.add(JSON.toJSONString(recordDTO));
|
|
||||||
}
|
|
||||||
|
|
||||||
// 追加日志内容
|
|
||||||
FileUtil.appendLines(outList, fileAbsolutePath, StandardCharsets.UTF_8);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void addAsync(LogRecordDTO logRecordDTO) {
|
|
||||||
logManagerThreadPool.executeLog(new TimerTask() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
logRefreshManager.putLog(logRecordDTO);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 日志刷新管理器
|
|
||||||
* <p>
|
|
||||||
* 该类暂存所有将要写出到磁盘的日志,使用内存缓冲区减少对磁盘IO的操作
|
|
||||||
* <p>
|
|
||||||
* 该类维护一个最大日志数和一个刷新日志间隔,满足任意一个条件即可触发从内存写出日志到磁盘的操作
|
|
||||||
*
|
|
||||||
* @author majianguo
|
|
||||||
* @since 2020/10/31 15:05
|
|
||||||
*/
|
|
||||||
class LogRefreshManager extends Thread {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Hutool日志对象
|
|
||||||
*/
|
|
||||||
private final Log log = LogFactory.get();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 刷新日志间隔(默认3秒),单位毫秒
|
|
||||||
*/
|
|
||||||
private final long sleepTime;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 满足多少条就强制刷新一次(默认300条),该值只是一个大约值,实际记录并不会一定等于该值(可能会大于该值,不可能小于该值)
|
|
||||||
*/
|
|
||||||
private final int maxCount;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 刷新数据时间标志,每次刷新都记录当前的时间戳,方便定时刷新准确判断上次刷新和本次刷新的时间间隔
|
|
||||||
*/
|
|
||||||
private final AtomicLong refreshMark = new AtomicLong();
|
|
||||||
|
|
||||||
public LogRefreshManager() {
|
|
||||||
this.sleepTime = 3000;
|
|
||||||
this.maxCount = 300;
|
|
||||||
}
|
|
||||||
|
|
||||||
public LogRefreshManager(long sleepTime) {
|
|
||||||
this.sleepTime = sleepTime;
|
|
||||||
this.maxCount = 300;
|
|
||||||
}
|
|
||||||
|
|
||||||
public LogRefreshManager(int maxCount) {
|
|
||||||
this.sleepTime = 3000;
|
|
||||||
this.maxCount = maxCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
public LogRefreshManager(long sleepTime, int maxCount) {
|
|
||||||
this.sleepTime = sleepTime;
|
|
||||||
this.maxCount = maxCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 未处理日志的消息队列
|
|
||||||
*/
|
|
||||||
private final Queue<LogRecordDTO> queue = new ConcurrentLinkedQueue<>();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 消息总数,队列的size方法会遍历一遍队列,所以自己维护大小
|
|
||||||
*/
|
|
||||||
public AtomicInteger count = new AtomicInteger(0);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 往队列内新增一条日志数据
|
|
||||||
*
|
|
||||||
* @param logRecordDTO 日志对象
|
|
||||||
* @author majianguo
|
|
||||||
* @since 2020/10/31 14:59
|
|
||||||
*/
|
|
||||||
public void putLog(LogRecordDTO logRecordDTO) {
|
|
||||||
|
|
||||||
int queueDataCount = count.get();
|
|
||||||
|
|
||||||
// 如果是第一条消息,刷新一次refreshMark
|
|
||||||
if (queueDataCount == 0) {
|
|
||||||
refreshMark.getAndSet(System.currentTimeMillis());
|
|
||||||
}
|
|
||||||
|
|
||||||
// 如果后续写入磁盘的操作有异常(磁盘满了),为了防止日志刷不出去导致OOM,内存中最大只保留maxCount数一倍的日志,后续日志将丢弃
|
|
||||||
if (queueDataCount >= (maxCount * 2)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
queue.offer(logRecordDTO);
|
|
||||||
count.incrementAndGet();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 刷新日志到磁盘的操作
|
|
||||||
*
|
|
||||||
* @author majianguo
|
|
||||||
* @since 2020/10/31 15:48
|
|
||||||
*/
|
|
||||||
private void refresh() {
|
|
||||||
// 让睡眠线程本次不要再调本方法,睡眠至下次看refreshMark的值再决定要不要调用本方法
|
|
||||||
refreshMark.getAndSet(System.currentTimeMillis());
|
|
||||||
|
|
||||||
// 获取总数
|
|
||||||
int num = count.getAndSet(0);
|
|
||||||
|
|
||||||
// 缓冲队列中所有的数据
|
|
||||||
List<LogRecordDTO> cacheAll = new ArrayList<>(num);
|
|
||||||
|
|
||||||
try {
|
|
||||||
// 在队列中读取num条数据,放入list
|
|
||||||
for (int i = 0; i < num; i++) {
|
|
||||||
LogRecordDTO item = queue.poll();
|
|
||||||
if (null == item) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
cacheAll.add(item);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 调用方法刷新到磁盘
|
|
||||||
addBatch(cacheAll);
|
|
||||||
|
|
||||||
} catch (Exception e) {
|
|
||||||
|
|
||||||
// 有异常把日志刷回队列,不要丢掉(这里可能会导致日志顺序错乱)
|
|
||||||
for (LogRecordDTO recordDTO : cacheAll) {
|
|
||||||
queue.offer(recordDTO);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 打印日志
|
|
||||||
if (log.isDebugEnabled()) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
log.error(e.getMessage());
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 日志数据定时执行器
|
|
||||||
* <p>
|
|
||||||
* 用于定时检测日志数据是否可以写入数据
|
|
||||||
*
|
|
||||||
* @author majianguo
|
|
||||||
* @since 2020/10/31 15:57
|
|
||||||
*/
|
|
||||||
private void timing() {
|
|
||||||
try {
|
|
||||||
// 如果是激活状态,且消息数大于零,且符合上次调用refresh方法到目前时间的间隔,那就调用一次refresh方法
|
|
||||||
if ((refreshMark.get() + sleepTime) <= System.currentTimeMillis() && count.get() > 0) {
|
|
||||||
refresh();
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
|
||||||
if (log.isDebugEnabled()) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
log.error(e.getMessage());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 日志数据监听器
|
|
||||||
* <p>
|
|
||||||
* 用于监听日志消息队列,达到设定的数就开始执行刷入硬盘的操作
|
|
||||||
*
|
|
||||||
* @author majianguo
|
|
||||||
* @since 2020/11/2 9:32
|
|
||||||
*/
|
|
||||||
private void listener() {
|
|
||||||
try {
|
|
||||||
// 判断如果队列里面的数据大于等于设定的最大消息数,就调用refresh方法刷新一次数据
|
|
||||||
if (count.get() >= maxCount) {
|
|
||||||
refresh();
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
|
||||||
if (log.isDebugEnabled()) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
log.error(e.getMessage());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@SuppressWarnings("InfiniteLoopStatement")
|
|
||||||
public void run() {
|
|
||||||
try {
|
|
||||||
for (; ; ) {
|
|
||||||
// 消息监听器
|
|
||||||
listener();
|
|
||||||
// 定时任务监听器
|
|
||||||
timing();
|
|
||||||
TimeUnit.MILLISECONDS.sleep(10);
|
|
||||||
}
|
|
||||||
} catch (InterruptedException e) {
|
|
||||||
if (log.isDebugEnabled()) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
log.error(e.getMessage());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -37,11 +37,6 @@
|
||||||
<artifactId>log-sdk-db</artifactId>
|
<artifactId>log-sdk-db</artifactId>
|
||||||
<version>${roses.version}</version>
|
<version>${roses.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
|
||||||
<groupId>cn.stylefeng.roses</groupId>
|
|
||||||
<artifactId>log-sdk-file</artifactId>
|
|
||||||
<version>${roses.version}</version>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<!--登录日志的业务-->
|
<!--登录日志的业务-->
|
||||||
<dependency>
|
<dependency>
|
||||||
|
|
|
@ -24,24 +24,15 @@
|
||||||
*/
|
*/
|
||||||
package cn.stylefeng.roses.kernel.log.starter;
|
package cn.stylefeng.roses.kernel.log.starter;
|
||||||
|
|
||||||
import cn.hutool.core.util.StrUtil;
|
|
||||||
import cn.hutool.system.SystemUtil;
|
|
||||||
import cn.stylefeng.roses.kernel.log.api.LogManagerApi;
|
import cn.stylefeng.roses.kernel.log.api.LogManagerApi;
|
||||||
import cn.stylefeng.roses.kernel.log.api.LogRecordApi;
|
import cn.stylefeng.roses.kernel.log.api.LogRecordApi;
|
||||||
import cn.stylefeng.roses.kernel.log.api.enums.LogSaveTypeEnum;
|
|
||||||
import cn.stylefeng.roses.kernel.log.api.expander.LogConfigExpander;
|
|
||||||
import cn.stylefeng.roses.kernel.log.api.pojo.log.SysLogProperties;
|
|
||||||
import cn.stylefeng.roses.kernel.log.api.threadpool.LogManagerThreadPool;
|
import cn.stylefeng.roses.kernel.log.api.threadpool.LogManagerThreadPool;
|
||||||
import cn.stylefeng.roses.kernel.log.db.DbLogManagerServiceImpl;
|
import cn.stylefeng.roses.kernel.log.db.DbLogManagerServiceImpl;
|
||||||
import cn.stylefeng.roses.kernel.log.db.DbLogRecordServiceImpl;
|
import cn.stylefeng.roses.kernel.log.db.DbLogRecordServiceImpl;
|
||||||
import cn.stylefeng.roses.kernel.log.db.service.SysLogService;
|
import cn.stylefeng.roses.kernel.log.db.service.SysLogService;
|
||||||
import cn.stylefeng.roses.kernel.log.db.service.impl.SysLogServiceImpl;
|
import cn.stylefeng.roses.kernel.log.db.service.impl.SysLogServiceImpl;
|
||||||
import cn.stylefeng.roses.kernel.log.file.FileLogManagerServiceImpl;
|
|
||||||
import cn.stylefeng.roses.kernel.log.file.FileLogRecordServiceImpl;
|
|
||||||
import cn.stylefeng.roses.kernel.log.requestapi.RequestApiLogRecordAop;
|
import cn.stylefeng.roses.kernel.log.requestapi.RequestApiLogRecordAop;
|
||||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
|
||||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
|
||||||
|
@ -54,96 +45,40 @@ import org.springframework.context.annotation.Configuration;
|
||||||
@Configuration
|
@Configuration
|
||||||
public class GunsLogAutoConfiguration {
|
public class GunsLogAutoConfiguration {
|
||||||
|
|
||||||
/**
|
|
||||||
* 日志配置的前缀
|
|
||||||
*/
|
|
||||||
public static final String SYS_LOG_PREFIX = "sys-log";
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 系统日志service
|
* 系统日志service
|
||||||
*
|
*
|
||||||
* @return sysLogService
|
|
||||||
* @author liuhanqing
|
* @author liuhanqing
|
||||||
* @since 2020/12/28 22:09
|
* @since 2020/12/28 22:09
|
||||||
*/
|
*/
|
||||||
@Bean
|
@Bean
|
||||||
@ConditionalOnMissingBean(SysLogService.class)
|
@ConditionalOnMissingBean(SysLogService.class)
|
||||||
@ConditionalOnProperty(prefix = SYS_LOG_PREFIX, name = "type", havingValue = "db")
|
|
||||||
public SysLogService sysLogService() {
|
public SysLogService sysLogService() {
|
||||||
return new SysLogServiceImpl();
|
return new SysLogServiceImpl();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 系统日志的配置
|
|
||||||
*
|
|
||||||
* @author liuhanqing
|
|
||||||
* @since 2020/12/20 14:17
|
|
||||||
*/
|
|
||||||
@Bean
|
|
||||||
@ConfigurationProperties(prefix = SYS_LOG_PREFIX)
|
|
||||||
public SysLogProperties sysLogProperties() {
|
|
||||||
return new SysLogProperties();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 每个请求接口记录日志的AOP
|
* 每个请求接口记录日志的AOP
|
||||||
* 根据配置文件初始化日志记录器
|
* <p>
|
||||||
* 日志存储类型:db-数据库,file-文件,默认存储在数据库中
|
* 根据配置文件初始化日志记录器,采用数据库存储
|
||||||
*
|
*
|
||||||
* @param sysLogProperties 系统日志配置文件
|
* @param sysLogService 系统日志service
|
||||||
* @param sysLogService 系统日志service
|
|
||||||
* @author liuhanqing
|
* @author liuhanqing
|
||||||
* @since 2020/12/20 13:02
|
* @since 2020/12/20 13:02
|
||||||
*/
|
*/
|
||||||
@Bean
|
@Bean
|
||||||
public RequestApiLogRecordAop requestApiLogRecordAop(SysLogProperties sysLogProperties, SysLogServiceImpl sysLogService) {
|
public RequestApiLogRecordAop requestApiLogRecordAop(SysLogService sysLogService) {
|
||||||
|
|
||||||
// 如果类型是文件
|
|
||||||
if (StrUtil.isNotBlank(sysLogProperties.getType())
|
|
||||||
&& LogSaveTypeEnum.FILE.getCode().equals(sysLogProperties.getType())) {
|
|
||||||
|
|
||||||
// 修改为从sys_config中获取日志存储位置
|
|
||||||
String fileSavePath = "";
|
|
||||||
if (SystemUtil.getOsInfo().isWindows()) {
|
|
||||||
fileSavePath = LogConfigExpander.getLogFileSavePathWindows();
|
|
||||||
} else {
|
|
||||||
fileSavePath = LogConfigExpander.getLogFileSavePathLinux();
|
|
||||||
}
|
|
||||||
|
|
||||||
return new RequestApiLogRecordAop(new FileLogRecordServiceImpl(fileSavePath, new LogManagerThreadPool()));
|
|
||||||
}
|
|
||||||
|
|
||||||
// 其他情况用数据库存储日志
|
|
||||||
return new RequestApiLogRecordAop(new DbLogRecordServiceImpl(new LogManagerThreadPool(), sysLogService));
|
return new RequestApiLogRecordAop(new DbLogRecordServiceImpl(new LogManagerThreadPool(), sysLogService));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 日志管理器
|
* 日志管理器
|
||||||
*
|
*
|
||||||
* @param sysLogProperties 系统日志配置文件
|
|
||||||
* @author liuhanqing
|
* @author liuhanqing
|
||||||
* @since 2020/12/20 18:53
|
* @since 2020/12/20 18:53
|
||||||
*/
|
*/
|
||||||
@Bean
|
@Bean
|
||||||
public LogManagerApi logManagerApi(SysLogProperties sysLogProperties) {
|
public LogManagerApi logManagerApi() {
|
||||||
|
|
||||||
// 如果类型是文件
|
|
||||||
if (StrUtil.isNotBlank(sysLogProperties.getType())
|
|
||||||
&& LogSaveTypeEnum.FILE.getCode().equals(sysLogProperties.getType())) {
|
|
||||||
|
|
||||||
// 修改为从sys_config中获取日志存储位置
|
|
||||||
String fileSavePath = "";
|
|
||||||
if (SystemUtil.getOsInfo().isWindows()) {
|
|
||||||
fileSavePath = LogConfigExpander.getLogFileSavePathWindows();
|
|
||||||
} else {
|
|
||||||
fileSavePath = LogConfigExpander.getLogFileSavePathLinux();
|
|
||||||
}
|
|
||||||
|
|
||||||
return new FileLogManagerServiceImpl(fileSavePath);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 其他情况用数据库存储日志
|
|
||||||
return new DbLogManagerServiceImpl();
|
return new DbLogManagerServiceImpl();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -154,7 +89,7 @@ public class GunsLogAutoConfiguration {
|
||||||
* @since 2021/3/4 22:16
|
* @since 2021/3/4 22:16
|
||||||
*/
|
*/
|
||||||
@Bean
|
@Bean
|
||||||
public LogRecordApi logRecordApi(SysLogServiceImpl sysLogService) {
|
public LogRecordApi logRecordApi(SysLogService sysLogService) {
|
||||||
return new DbLogRecordServiceImpl(new LogManagerThreadPool(), sysLogService);
|
return new DbLogRecordServiceImpl(new LogManagerThreadPool(), sysLogService);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -21,7 +21,6 @@
|
||||||
<module>log-business-manage</module>
|
<module>log-business-manage</module>
|
||||||
<module>log-business-requestapi</module>
|
<module>log-business-requestapi</module>
|
||||||
<module>log-sdk-db</module>
|
<module>log-sdk-db</module>
|
||||||
<module>log-sdk-file</module>
|
|
||||||
<module>log-spring-boot-starter</module>
|
<module>log-spring-boot-starter</module>
|
||||||
</modules>
|
</modules>
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue