§ 开发约束

§ 日志开发

§ 日志级别

日志级别 级别描述 信息类别
DEBUG 细粒度的级别。对出错以及系统调试时输出的信息、事件进行记录。程序的关键路径,输出较频繁。 调试信息
INFO 粗粒度的级别。在正常运行状态中,对重要流程/事件以及表示系统健康度的信息、事件进行记录。 此级别不允许输出SQL语句等调试用敏感信息。 一般信息
WARN 有潜在风险的、不会造成大危害的错误发生(往往由应用餐部因素造成,如不正确的输入数据等)。 错误信息
ERROR 应用发生错误(包括业务错误和技术错误),但后续流程还能继续进行。 错误信息
FATAL 应用发生严重错误(技术型异常),应用服务停止。 错误信息

系统级日志级别:ERROR

§ 日志打印

Debug级别日志输出,需要增加debug状态判断

if (logger.isDebugEnabled()) {
    logger.debug("菜单信息:{}", adminSmMenu);
}
1
2
3

日志输出时,避免逻辑操作,如下日志输出,user.getRole().getId()会存在空指针的情况

if ("admin".equals(user.getName) {
    logger.debug("菜单信息:{}", user.getRole().getId());
}
1
2
3

§ 敏感信息

任何级别的系统日志中不允许出现客户相关的:

  • 指纹、人脸等生物特征的特征码
  • 信息加密所使用的密钥串
  • 密码,明文密码、密文密码均不允许出现,可以以**的形式代替,但是的位数不能暴露密码的长度信息
  • 银行卡相关的磁道信息、验证信息,包括2磁、3磁及相关信息
  • IC卡相关的芯片信息,包括ARQC、等效2磁等信息
  • (暂定为非强制性规范)客户姓名、手机号、证件号建议进行部分隐藏,隐藏规则如下:

§ 日志文件输出

§ 日志记录的内容应总体满足如下规则

  • 应用程序日志原则上使用UTF-8字符编码,以便于将来的日志文件分析
  • 不应使用系统输出进行日志记录。例如 System.out. print,printStackTrace等方法
  • 不应将应用日志写入生产环境操作系统、以及其他中间件产品的日志文件中。例如 SystemErr.log、SystemOut.log等文件
  • 日志在记录时无论成功与否,都不应改变业务逻辑

§ 输出格式

系统默认提供如下格式,如果启用了链路跟踪,将在 [main, , ]中打印链路中traceId和spanId的信息:

[${applicationName}, ${ip}] %-5p %d{yyyy-MM-dd HH:mm:ss.SSS} [%t, %X{X-B3-TraceId:-}, %X{X-B3-SpanId:-}] %c.%M:%L - %m%n
1

即输出的日志示例如下:

[yusp-app-oca, 172.16.20.208] INFO 2019-03-08 18:40:27.766 [main, , ] cn.com.yusys.yusp.commons.config.ExcelTaskAutoConfiguration.getExcelRemoteCall:55 - 加载缺省的ExcelRemoteCallDefaultImpl
[yusp-app-oca, 172.16.20.208] INFO 2019-03-08 18:40:28.680 [main, , ] org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping.register:549 - Mapped "{[/api/pdfdemo/gethtml],methods=[GET]}" onto public org.springframework.web.servlet.ModelAndView cn.com.yusys.yusp.admin.web.rest.AdminPdfDemoResource.gethtml()
[yusp-app-oca, 172.16.20.208] INFO 2019-03-08 18:40:28.693 [main, , ] org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping.register:549 - Mapped "{[/api/pdfdemo/getpdf],methods=[GET]}" onto public org.springframework.web.servlet.ModelAndView cn.com.yusys.yusp.admin.web.rest.AdminPdfDemoResource.getpdf(java.lang.String)
[yusp-app-oca, 172.16.20.208] INFO 2019-03-08 18:40:28.693 [main, , ] org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping.register:549 - Mapped "{[/api/adminsmauthinfo/delete/{id}],methods=[POST]}" onto public cn.com.yusys.yusp.commons.web.rest.dto.ResultDto<java.lang.Integer> cn.com.yusys.yusp.admin.web.rest.AdminSmAuthInfoResource.delete(java.lang.String)
1
2
3
4

§ 可用日志属性列表

level 输出日志级别 基础
thread 输出产生日志的线程名。 基础
class 输出执行记录请求的调用者的全限定名 基础
line 输出执行日志请求的行号 基础
message 输出应用程序提供的信息 基础
exception{X} 异常栈信息 基础
logger{X} 输出类名 基础
PID 进程ID 基础
springAppName 记录跨度的应用程序的名称 基础
X-B3-SpanId 发生特定操作的ID springCloud扩展
X-B3-TraceId 包含跨度的延迟图的ID springCloud扩展
X-B3-ParentSpanId 日志是否应该被导出到Zipkin与否 springCloud扩展
X-Span-Export 父级操作ID springCloud扩展
timestamp 时间戳 ELK扩展-默认打印,不需要配置
host 服务主机IP ELK扩展-默认打印,不需要配置
applicationName 应用名称
IP 应用ip地址,自定义输出字段

§ 关于pattern 控制输出的内容

%c,%c{参数},%C{参数},%class{参数},%lo{参数},%logger{参数}:输出类名称

%c org.apache.com.te.Foo org.apache.com.te.Foo
%c{1} org.apache.com.te.Foo Foo
%c{2} org.apache.com.te.Foo te.Foo
%c{1.} org.apache.com.te.Foo o.a.c.t.Foo
%c{1.1.!} org.apache.com.te.Foo o.a.!.!.Foo
%c{.} org.apache.com.te.Foo ….Foo

%d{参数},%date{参数}:输出时间。参数可以是text.SimpleDateFormat字符拼接而成,也可以使用系统默认

%d 2006-10-20 14:06:49,812
%date 2006-10-20 14:06:49,812
%date{ISO8601} 2006-10-20 14:06:49,812
%date{HH:mm:ss.SSS} 14:06:49.812
%date{dd MMM yyyy ;HH:mm:ss.SSS} 20 oct. 2006;14:06:49.812

%L,%line:输出执行日志请求的行号。尽量避免使用,除非执行速度不造成任何问题。

%m或%msg或%message:输出日志信息

%M或%method:输出方法名

%p,%le,%level:输出日志级别

%t,%thread:输出产生日志的线程名

§ ide模板提供的默认日志

如下为通过ide创建模板时提供的默认logback日志配置文件

<?xml version="1.0" encoding="UTF-8"?>
<!-- 启用每隔60s读取该文件,刷新配置信息 -->
<configuration scan="true" scanPeriod="60000">
    <!-- 导入SpringBoot默认的logback配置 -->
    <include resource="org/springframework/boot/logging/logback/defaults.xml" />
    <!-- 通过spring上下文获取对应的配置信息 -->
    <!-- 获取日志文件的路径(取自bootstrap.yml/bootstrap.properties文件) -->
    <springProperty scope="context" name="logPath" source="logging.path" defaultValue="../logs"></springProperty>
    <!-- 获取日志文件的名称(取自bootstrap.yml/bootstrap.properties文件) -->
    <springProperty scope="context" name="logFile" source="logging.file" defaultValue="application.log"></springProperty>
    <!-- 获取当前启动的应用名称 (取自bootstrap.yml/bootstrap.properties文件)-->
    <springProperty scope="context" name="applicationName" source="spring.application.name"></springProperty>
    <!-- 获取当前启动应用的日志级别(取自bootstrap.yml/bootstrap.properties文件) -->
    <springProperty scope="context" name="logLevel" source="logging.level.root" defaultValue="INFO"></springProperty>
    <!-- 自定义属性,当前自定义为获取服务所在机器IP地址 -->
    <define name="ip" class="cn.com.yusys.yusp.commons.log.CustomizedApplicationIP"></define>
    <!-- logback上下文属性配置 -->
    <!-- 日志文件输出格式定义(如不定义,默认取defaults.xml中配置) -->
    <property name="FILE_LOG_PATTERN" value="[${applicationName}, ${ip}] %-5p %d{yyyy-MM-dd HH:mm:ss.SSS} [%t, %X{X-B3-TraceId:-}, %X{X-B3-SpanId:-}] %c.%M:%L - %m%n"/>
    <!-- 控制台日志格式输出定义(如不定义,默认取defaults.xml中配置) -->
    <property name="CONSOLE_LOG_PATTERN" value="[${applicationName}, ${ip}] %-5p %d{yyyy-MM-dd HH:mm:ss.SSS} [%t, %X{X-B3-TraceId:-}, %X{X-B3-SpanId:-}] %c.%M:%L - %m%n"/>
    <include resource="org/springframework/boot/logging/logback/console-appender.xml" />
    
    <!-- 默认的日志文件输出 -->
    <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <append>true</append>
        <encoder>
            <pattern>${FILE_LOG_PATTERN}</pattern>
            <charset>utf8</charset>
        </encoder>
        <file>${logPath}/${logFile}</file>
        <!-- 日志生成策略,按日备份,最大保留30天,每128M切分一个日志文件 -->
        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
            <fileNamePattern>${logPath}/%d{yyyy-MM-dd}/${logFile}.%i.log</fileNamePattern>
            <maxHistory>7</maxHistory>
            <maxFileSize>128MB</maxFileSize>
            <totalSizeCap>1GB</totalSizeCap>
        </rollingPolicy>
    </appender>
    
    <!-- 日志输出控制 -->
    <root level="${logLevel}">
        <appender-ref ref="FILE" />
        <appender-ref ref="CONSOLE" />
    </root>
</configuration>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46

其中的备份策略见rollingPolicy节点,默认为每128M切换一个文件,最大每天为1G的日志文件,保存历史为7天

其中日志输出到控制台和日志文件,日志文件的路径见file节点配置

§ 自定义日志输出字段属性

自定义日志属性的开发可参见CustomizedApplicationIP类,配置方式见上一章节define节点配置方式

示例代码如下:

public class CustomizedApplicationIP extends ClassicConverter implements PropertyDefiner {
 
    private static String ip;
 
    static {
        try {
            ip = InetAddress.getLocalHost().getHostAddress();
        } catch (UnknownHostException e) {
            e.printStackTrace();
        }
    }
 
    @Override
    public String convert(ILoggingEvent event) {
        return ip;
    }
 
    @Override
    public String getPropertyValue() {
        return ip;
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
最后更新于: 4/28/2022, 4:58:56 PM