优化:基于阿里巴巴 Java 开发手册(黄山版)优化日志配置

1.异常日志>日志规约>第2条:
【强制】日志文件至少保存 15 天,因为有些异常具备以“周”为频次发生的特点。对于当天日志,以“应用名.log”来保存,保存在/{统一目录}/{应用名}/logs/目录下,过往日志格式为:{logname}.log.{保存日期},日期格式:yyyy-MM-dd
正例:以 mppserver 应用为例,日志保存/home/admin/mppserver/logs/mppserver.log,历史日志名称为 mppserver.log.2021-11-28
2.异常日志>日志规约>第3条:
【强制】根据国家法律,网络运行状态、网络安全事件、个人敏感信息操作等相关记录,留存的日志不少于六个月,并且进行网络多机备份。
3.异常日志>日志规约>第9条:
【强制】异常信息应该包括两类信息:案发现场信息和异常堆栈信息。如果不处理,那么通过关键字throws 往上抛出。
正例:logger.error("inputParams: {} and errorMessage: {}", 各类参数或者对象 toString(), e.getMessage(), e);
4.异常日志>日志规约>第12条:
【推荐】可以使用 warn 日志级别来记录用户输入参数错误的情况,避免用户投诉时,无所适从。如非必要,请不要在此场景打出 error 级别,避免频繁报警。
说明:注意日志输出的级别,error 级别只记录系统逻辑出错、异常或者重要的错误信息。
This commit is contained in:
Charles7c 2023-03-05 00:15:01 +08:00
parent 47fa1422bb
commit 44fa7266b6
5 changed files with 22 additions and 23 deletions

View File

@ -97,7 +97,7 @@ public class GlobalExceptionHandler {
@ResponseStatus(HttpStatus.BAD_REQUEST)
@ExceptionHandler(BadRequestException.class)
public R handleBadRequestException(BadRequestException e, HttpServletRequest request) {
log.error("请求地址'{}',自定义验证失败", request.getRequestURI(), e);
log.warn("请求地址'{}',自定义验证失败", request.getRequestURI(), e);
LogContextHolder.setErrorMsg(e.getMessage());
return R.fail(HttpStatus.BAD_REQUEST.value(), e.getMessage());
}
@ -108,7 +108,7 @@ public class GlobalExceptionHandler {
@ResponseStatus(HttpStatus.BAD_REQUEST)
@ExceptionHandler(BindException.class)
public R handleBindException(BindException e, HttpServletRequest request) {
log.error("请求地址'{}',参数验证失败", request.getRequestURI(), e);
log.warn("请求地址'{}',参数验证失败", request.getRequestURI(), e);
String errorMsg = StreamUtils.join(e.getAllErrors(), DefaultMessageSourceResolvable::getDefaultMessage, "");
LogContextHolder.setErrorMsg(errorMsg);
return R.fail(HttpStatus.BAD_REQUEST.value(), errorMsg);
@ -120,7 +120,7 @@ public class GlobalExceptionHandler {
@ResponseStatus(HttpStatus.BAD_REQUEST)
@ExceptionHandler(ConstraintViolationException.class)
public R constraintViolationException(ConstraintViolationException e, HttpServletRequest request) {
log.error("请求地址'{}',参数验证失败", request.getRequestURI(), e);
log.warn("请求地址'{}',参数验证失败", request.getRequestURI(), e);
String errorMsg = StreamUtils.join(e.getConstraintViolations(), ConstraintViolation::getMessage, "");
LogContextHolder.setErrorMsg(errorMsg);
return R.fail(HttpStatus.BAD_REQUEST.value(), errorMsg);
@ -132,7 +132,7 @@ public class GlobalExceptionHandler {
@ResponseStatus(HttpStatus.BAD_REQUEST)
@ExceptionHandler(MethodArgumentNotValidException.class)
public R handleMethodArgumentNotValidException(MethodArgumentNotValidException e, HttpServletRequest request) {
log.error("请求地址'{}',参数验证失败", request.getRequestURI(), e);
log.warn("请求地址'{}',参数验证失败", request.getRequestURI(), e);
String errorMsg = ExceptionUtils
.exToNull(() -> Objects.requireNonNull(e.getBindingResult().getFieldError()).getDefaultMessage());
LogContextHolder.setErrorMsg(errorMsg);
@ -147,7 +147,7 @@ public class GlobalExceptionHandler {
public R handleMethodArgumentTypeMismatchException(MethodArgumentTypeMismatchException e,
HttpServletRequest request) {
String subMsg = StrUtil.format("参数名:'{}',期望参数类型:'{}'", e.getName(), e.getParameter().getParameterType());
log.error("请求地址'{}',参数转换失败。方法:'{}'{}", request.getRequestURI(),
log.warn("请求地址'{}',参数转换失败。方法:'{}'{}", request.getRequestURI(),
Objects.requireNonNull(e.getParameter().getMethod()).getName(), subMsg, e);
LogContextHolder.setErrorMsg(subMsg);
return R.fail(HttpStatus.BAD_REQUEST.value(), subMsg);
@ -170,7 +170,7 @@ public class GlobalExceptionHandler {
@ResponseStatus(HttpStatus.BAD_REQUEST)
@ExceptionHandler(MaxUploadSizeExceededException.class)
public R handleMaxUploadSizeExceededException(MaxUploadSizeExceededException e, HttpServletRequest request) {
log.error("请求地址'{}',上传文件失败,文件大小超过限制", request.getRequestURI(), e);
log.warn("请求地址'{}',上传文件失败,文件大小超过限制", request.getRequestURI(), e);
String sizeLimit = StrUtil.subBetween(e.getMessage(), "The maximum size ", " for");
String errorMsg = String.format("请上传小于 %s MB 的文件", NumberUtil.parseLong(sizeLimit) / 1024 / 1024);
LogContextHolder.setErrorMsg(errorMsg);

View File

@ -27,7 +27,6 @@ import lombok.extern.slf4j.Slf4j;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.write.style.column.LongestMatchColumnWidthStyleStrategy;
import com.esotericsoftware.minlog.Log;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.URLUtil;
@ -90,7 +89,7 @@ public class ExcelUtils {
// 自动转换大数值
.registerConverter(new ExcelBigNumberConverter()).sheet(sheetName).doWrite(list);
} catch (Exception e) {
Log.error("Export excel occurred an error.", e);
log.error("Export excel occurred an error: {}. fileName: {}.", e.getMessage(), fileName, e);
throw new ServiceException("导出 Excel 出现错误");
}
}

View File

@ -56,16 +56,16 @@ public class FileUtils {
String originalFilename = multipartFile.getOriginalFilename();
String extensionName = FileNameUtil.extName(originalFilename);
String filename;
String fileName;
if (isKeepOriginalFilename) {
filename = String.format("%s-%s.%s", FileNameUtil.getPrefix(originalFilename),
fileName = String.format("%s-%s.%s", FileNameUtil.getPrefix(originalFilename),
DateUtil.format(LocalDateTime.now(), StringConsts.PURE_DATE_TIME_MS_PATTERN), extensionName);
} else {
filename = String.format("%s.%s", IdUtil.fastSimpleUUID(), extensionName);
fileName = String.format("%s.%s", IdUtil.fastSimpleUUID(), extensionName);
}
try {
String pathname = filePath + filename;
String pathname = filePath + fileName;
File dest = new File(pathname).getCanonicalFile();
// 如果父路径不存在自动创建
if (!dest.getParentFile().exists()) {
@ -77,7 +77,7 @@ public class FileUtils {
multipartFile.transferTo(dest);
return dest;
} catch (Exception e) {
log.error(e.getMessage(), e);
log.error("Upload file occurred an error: {}. fileName: {}.", e.getMessage(), fileName, e);
}
return null;
}

View File

@ -119,7 +119,7 @@ public class QueryHelper {
// 解析查询条件
parse(queryAnnotation, field.getName(), fieldValue, queryWrapper);
} catch (Exception e) {
log.error(e.getMessage(), e);
log.error("Build query occurred an error: {}. Query: {}, Field: {}.", e.getMessage(), query, field, e);
} finally {
field.setAccessible(accessible);
}

View File

@ -36,19 +36,19 @@
<!-- 输出日志到文件 -->
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!-- 正在记录的日志文件的路径及文件名 -->
<file>${LOG_PATH}/${APP_NAME}.log</file>
<!-- 滚动策略:基于时间归档日志文件 -->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- 归档日志文件的路径及文件名 -->
<fileNamePattern>${LOG_PATH}/${APP_NAME}.log.%d{yyyy-MM-dd}.gz</fileNamePattern>
<!-- 归档日志最大保留数量(取决于 fileNamePattern 配置的规则,例如:配置归档为每天 1 个文件,那么保留 15 个也可以理解为是保留 15 天) -->
<maxHistory>15</maxHistory>
</rollingPolicy>
<encoder>
<pattern>${FILE_LOG_PATTERN}</pattern>
<charset>${LOG_CHARSET}</charset>
</encoder>
<!-- 循环政策:基于时间和大小创建日志文件 -->
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<!-- 日志文件输出的文件名 -->
<fileNamePattern>${LOG_PATH}/%d{yyyy-MM-dd, aux}/${APP_NAME}.%d{yyyy-MM-dd_HH}.%i.log</fileNamePattern>
<!-- 日志保存 10 天(一小时生成一个,一天 24 个文件) -->
<maxHistory>240</maxHistory>
<!-- 单个日志文件最大的大小 -->
<maxFileSize>20MB</maxFileSize>
</rollingPolicy>
</appender>
<!-- 输出日志到文件(异步) -->