⼤数据JAVA⽇志规范
⽂章⽬录
⼀、前⾔
⼀个在⽣产环境⾥运⾏的程序如果没有⽇志是很让维护者提⼼吊胆的,有太多杂乱⼜⽆意义的⽇志也是令⼈伤神。程序出现问题时候,从⽇志⾥如果发现不了问题可能的原因是很令⼈受挫的。本⼿册为如何在Java程序⾥写好⽇志提供指引。
⼀般来说⽇志分为两种:业务⽇志和异常⽇志,使⽤⽇志我们希望能达到以下⽬标:
1. 对程序运⾏情况的记录和监控;
2. 在必要时可详细了解程序内部的运⾏状态;
3. 对系统性能的影响尽量⼩;
⼆、⽇志框架
Java的⽇志框架太多了,常⽤的有Log4j 或 Log4j2、Logback等。
说明:SLF4J是为各种Logging API提供⼀个简单统⼀的接⼝,需要结合具体框架进⾏使⽤。
2.1 【强制】约定单个项⽬内部使⽤SLF4J+Log4j2。
各⽇志框架之间的功能优异、性能差别不在本⼿册的讨论范围。
取舍的关键在于开源协议:
logback - GPL协议不允许闭源,即产品销售时必须提供源码
log4j2 - apache协议允许闭源
依赖引⽤ SFL4J+Log4j2:
Gradle:
compile 'org.apache.logging.log4j:'
compile 'org.apache.logging.log4j:'
compile 'org.apache.logging.log4j: '
Maven:
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version&</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version&</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-slf4j-impl</artifactId>
<version&</version>
</dependency>
2.1.1 【强制】在引⼊⽇志框架依赖时,要把其他⽇志框架排除
否则会造成依赖冲突,SLF4J框架⽆法判断应该使⽤何种框架。如下图:
2.1.2 【强制】在打包fat-jar时,禁⽌打包任何⽇志框架
发布到⼤数据平台上运⾏时会造成依赖冲突,因为各个组件本⾝已经有⽇志框架。
三、⽇志⽂件
3.1 ⽇志⽬录
3.1.1【强制】所有应⽤须在⽇志⽬录下创建专属⽬录
应⽤所有⽇志都应保存在⽇志⽬录下,禁⽌将应⽤⽇志放置到应⽤部署⽬录。
正例:
/appcom/logs/bdp-mask/
错误:
/appcom/Install//logs/
3.1.2 【推荐】⼀个服务有多种不同的应⽤,在同⼀个⽬录下建⽴⼦⽬录区分。正例:
/appcom/logs/spark/spark-submit
/appcom/logs/spark/spark-sql
/appcom/logs/spark/spark-thriftserver
3.2 ⽇志滚动
3.2.1【强制】按⼤⼩滚动
应⽤⽇志设置为按⼤⼩滚动,每个⽂件1GB,备份10个⽂件。应⾄少保留最近⼀周的⽇志。
1、避免占⽤过⼤磁盘空间,影响整台机器的使⽤。
2、单个⽇志⽂件过⼤,会影响⽇志打印速度,进⽽影响到整个应⽤的性能。
appender:org.apache.log4j.RollingFileAppender
MaxFileSize:1GB
MaxBackupIndex:10
3.2.2 按时间滚动
若有特殊要求,也可按时间滚动。但必须做好以下准备:
1. 确保⽇志所在磁盘空间充⾜,并关注监控告警。
2. 配置定时任务删除历史⽇志⽂件。原则上只保留最近15天的⽇志,两周时间。
3.2.3 命名规范
3.2.3.1 【强制】appName[-⽇志类型]-启动⽤户-主机名.log
appName: 统⼀使⽤⼦系统英⽂名称,若⼀个⼦系统部署了多个服务,则再加上服务名称。
⽇志类型:可选项。添加这个选项的好处:通过⽂件名就可知道⽇志⽂件属于什么类型,什么⽬的,也有利于归类查。
正例:
⼀个⼦系统多个服务
脱敏服务端业务⽇志:bdp-mask-server-hadoop-bdphdp02jobs01.log
脱敏服务端访问⽇志:bdp-mask-server-access-hadoop-bdphdp02jobs01.log
脱敏客户端⽇志:bdp-mask-client-hadoop-bdphdp02jobs01.log
⼀个⼦系统⼀个服务
数据质量服务端⽇志:bdp-dqm-hadoop-bdphdp02jobs01.log
数据质量UI⽇志:bdp-dqmui-hadoop-bdphdp02jobs01.log
说明:
此命名⽅式参考hadoop,CDH等服务的⽇志命名格式。
⽇志⽂件逻辑上分开更利于⽇志管理。
性能上,机械硬盘如果是单⽂件写可以⼀定程度利⽤磁盘顺序写提⾼性能。
错误:
info.log
server.log
app.log
3.2.4 ⽇志重复打印
3.2.
4.1 【强制】⾃定义⽇志appender时,设置additivity=false
避免重复打印⽇志,浪费磁盘空间。若未设置,会在root、⾃定义appender中同时打印。
正例:
<logger name="com.demo.bdp.mask.access"additivity="false">
3.3 输出格式
3.3.1 【强制】统⼀格式:输出⽇期、时间(精确到毫秒),⽇志级别,线程名,appender的名称(⼀般是类名,只保留最后两级),消息
⽇志内容可以更多,但不能少。
正例:
%d{yyyy-MM-dd HH:mm:ss,SSS} %p [%t] %c{2}: %m%n
3.4 ⽇志变量
3.4.1【强制】使⽤SLF4J定义变量
不可直接使⽤⽇志系统(Log4j、Logback)中的API,有利于统⼀维护各个类的⽇志处理⽅式。
3.4.2 【强制】⽇志变量统⼀定义成static final,变量名⽤⼤写
3.4.3 【推荐】⽇志变量定义为private,由该类独占
通过class初始化⽇志变量时,会以该class作为输出的类名,若混⽤⽇志变量,会导致⽇志输出的类名相同,真正输出⽇志的类被隐藏起来,不利于排查问题。
正例:
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
private static final Logger LOG = Logger(Abc.class)
3.5 堆栈打印
3.5.1 【强制】输出Exception的全部Throwable信息
因为(msg)和(Message())这样的⽇志输出⽅法会丢失掉最重要的StackTrace类调⽤堆栈信息。
正例:
void foo(){
try{
// do something
}catch(Exception e){
<(“Bad things happened!”, e);
}
}
错误:
void foo(){
try{
// do something
}catch(Exception e){
<(“Bad things happened!”);
<(e.getMessage());
}
}
3.5.2 【强制】不允许记录⽇志后⼜抛出异常
这样会多次记录⽇志,影响排查问题。
错误:
void foo(){
try{
// do something
}catch(Exception e){
<(“Bad things happened!”, e);
throw new LogException(“Bad things happened!”, e);
}
}
3.5.3 【强制】在服务端应⽤中不允许出现System.out.print、System.out.println、println、print、printStackTrace等语句,将⽇志直接打印到标准输出
错误:
void foo(){
try{
// do something
}catch(Exception e){
System.out.Message());
e.printStackTrace();
}
}
3.6 ⽇志级别
3.6.1 【强制】对trace/debug/info级别的⽇志输出,必须使⽤条件输出形式或者使⽤占位符的⽅式
说明:
LOG.debug("Processing trade with id: "+ id +" and symbol: "+ symbol);
如果⽇志级别是warn,上述⽇志不会打印,但是会执⾏字符串拼接操作,如果symbol是对象,会执⾏toString()⽅法,浪费了系统资源,执⾏了上述操作,最终⽇志却没有打印。
正例:(条件)建设采⽤如下⽅式
if(LOG.isDebugEnabled()){
LOG.debug("Processing trade with id: "+ id +" and symbol: "+ symbol);
}
正例:(占位符)
LOG.debug("Processing trade with id: {} and symbol : {} ", id, symbol);
3.7 ⽇志内容
3.7.1 异常⽇志
3.7.1.1 【强制】禁⽌简单地输出⼀个错误代码,或者只是简单地输出失败
出现异常时必须明确打印正在进⾏何种⾏为时出错,要能指引运维⼈员如何排查问题。
正确:
<(“Failed to connect to Hive metastore: thrift://bdphdp020001:9083. Please check Hive metastore connection number.”, e);
mui框架常用组件有哪些(“Error saving HQL to file:/data/bdp/tmp/xxx.hql. Please check the disk information”, e);
<(“Failed to read config. File not found:/appcom/ Please check the file.”);
错误:
<(“1006”);
<(“Failed”);
3.7.1.2 【强制】异常信息应该包括四类信息
操作内容。当前正在进⾏何种操作时出错。
关键参数。⽤户、开发、运维关⼼的参数,能够确认是哪⼀个任务。
运维SOP。能够指引运维⼈员如何处理问题。
异常堆栈信息。
如果不处理,必须通过关键字throws往上抛出。
正例:
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论