进阶之路:Java 日志框架全画传(中)
ccwgpt 2024-10-01 08:12 36 浏览 0 评论
导读:随着互联网和大数据的蓬勃发展,分布式日志系统以及日志分析系统得到了广泛地应用。目前,几乎在所有应用程序中,都会用到各种各样的日志框架来记录程序的运行信息。鉴于此,工程师十分有必要熟悉主流的日志记录框架。
作者 | 书澜
前言
本篇为《进阶之路:Java 日志框架全画传》系列中篇,将结合具体案例介绍日志使用中需要遵循的规范及注意事项。
上篇解读了主流 Java 日志框架,欢迎关注昨日推送。
日志的格式和级别
在使用日志框架的时候,可以根据应用的诉求在日志配置文件中去自定义日志打印格式和日志级别等信息。如下所示,为 logback.xml 配置样例,其中对配置文件中的关键信息做了解释,其它日志框架的使用示例将在下一部分介绍。
<?xml version="1.0" encoding="UTF-8"?>
<configuration debug="false">
<!--定义日志文件的存储地址 勿在 LogBack 的配置中使用相对路径-->
<property name="LOG_HOME" value="/home" />
<!-- 控制台输出 -->
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<!--格式化输出:%d 表示日期,%thread 表示线程名,%-5level:级别从左显示 5 个字符宽度,%msg:日志消息,%n 是换行符-->
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
</encoder>
</appender>
<!-- 按照每天生成日志文件 -->
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!--日志文件输出的文件名-->
<FileNamePattern>${LOG_HOME}/TestWeb.log.%d{yyyy-MM-dd}.log</FileNamePattern>
<!--日志文件保留天数-->
<MaxHistory>30</MaxHistory>
</rollingPolicy>
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<!-- 日志输出格式:%d 表示日期时间,%thread 表示线程名,%-5level:级别从左显示 5 个字符宽度 %logger{50} 表示 logger 名字最长 50 个字符,否则按照句点分割。%msg:日志消息,%n 是换行符 -->
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
</encoder>
<!--日志文件最大的大小-->
<triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
<MaxFileSize>10MB</MaxFileSize>
</triggeringPolicy>
</appender>
<!-- 日志输出级别 -->
<root level="INFO">
<appender-ref ref="STDOUT" />
</root>
</configuration>
- 日志命名和保持期限
在公开的阿里巴巴 java 开发手册中对日志规范也有相关介绍,在此,笔者介绍其中两条规范,即日志命名方式和日志保存期限。
- 日志命名方式
appName_logType_logName.log
其中 appName 表示应用名;logType 表示日志类型,推荐分类有 stats,monitor,visit 等;logName 为日志描述,这种命名好处是可以快速清晰地了解日志文件类型和目的,便于归类查找。
- 日志保持期限
如何确定日志保持期限是个比较棘手的问题,如果日志存放时间过长,会消耗大量存储资源,甚至会导致磁盘压力过大影响系统稳定性;如果日志存放时间过短,可能导致日志数据“丢失”,出现问题时无法追溯。阿里 java 开发手册中对日志文件保存期限的建议是至少保存 15 天。在实际应用中,可以根据日志文件的重要程度、文件大小以及磁盘空间自行调整,此外,还可以对日志进行监控,定期转储。
- 日志等级
通常,日志记录的优先级分为 OFF、FATAL、ERROR、WARN、INFO、DEBUG、ALL 或自定义的级别。Log4j 建议只使用四个级别,优先级从高到低分别是 ERROR、WARN、INFO、DEBUG。通过在日志框架的配置文件中设置日志级别,可以控制应用程序中相应级别的日志信息开关。比如配置为 INFO 级别,那么只有等于及高于这个级别的日志才进行处理,应用程序中所有 DEBUG 级别的日志信息不会被打印出来。需要说明的是,日志等级不仅关乎“详细程度”,还关系到适用场景、服务对象等。常见日志等级的说明如下:
- ALL:打印所有的日志。
- OFF:闭所有的日志输出。
- ERROR:错误信息,包括错误的类型,错误的内容,位置和场景,是否可恢复等。只有当错误会影响到系统的正常运行时,才作为信息输出。
- WARN:起到提醒作用,虽然应用程序目前运行正常,但存在隐含的风险。
- INFO:记录系统的基本运行过程、运行状态、关键信息。
- DEBUG:系统运行过程与状态的细节信息,可用于调试。
- TRACE:系统结构与内容的细节信息,比如一些关键对象的内容,函数调用参数、结果等。
- 日志格式
通过配置日志输出格式可以控制输出日志信息的内容和样式。以上面日志配置文件 logback.xml 为例,其中 pattern 标签定义了日志的输出格式,默认参数如下表格所示。
除了上述默认的日志格式参数,Logback 还支持日志格式自定义配置,比如,希望每条日志能打印 ip 地址,实现方式如下:
- step1:新建一个类 IPLogConfig,重写 convert 方法,实现 ip 获取。
public class IPLogConfig extends ClassicConverter {
@Override
public String convert(ILoggingEvent event) {
try {
return InetAddress.getLocalHost().getHostAddress();
} catch (UnknownHostException e) {
e.printStackTrace();
}
return null;
}
}
- step2: 修改 logback.xml 配置。
<!--配置规则类的位置-->
<conversionRule conversionWord="ip" converterClass="com.test.conf.IPLogConfig" />
<appender name="Console" class="ch.qos.logback.core.ConsoleAppender">
<layout>
<pattern>[ip=%ip] %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
</layout>
</appender>
与 Logback 的日志输出格式配置相比,log4j 的输出格式配置有所不同,主要参数配置如下所示:
日志使用注意事项
本节将结合例子介绍日志应用中需要注意的基础事项,如异常记录、对象实例记录、日志监控、日志分类等。
- 异常日志如何记录
记录异常时一定要输出异常堆栈信息。如果没有完整的堆栈信息,那么一旦应用程序出现异常,维护人员将很难定位问题。
示例:某应用对处理链路进行功能点的拆分,每个功能点的失败都会抛异常。在服务入口处对异常日志进行分类记录。
try {
this.startOrderProcess(request, result, processName);
} catch (ProductBizException e) {
if (CollectionUtils.isNotEmpty(e.getErrorMessages())) {
e.getErrorMessages().forEach(errorMessage -> {
log.error("biz process error" + e.getMessage(), e);
});
}
} catch (ProductSystemException ex) {
log.error("system error" + ex.getMessage(), ex);
} catch (TMFRuntimeException e) {
ErrorMessage errorMessage = e.getErrorMessage();
if (null != errorMessage) {
log.error("tmf runtime error" + e.getMessage(), e);
}
}
对象实例如何记录
日志中如果输出对象实例,要确保实例类重写了 toString 方法,否则只会输出对象的 hashCode 值,毫无意义。此外,也可以通过 java 反射来获取对应的属性。主要好处是当增加或修改属性的时候,不需要修改 toString 方法,通常采用 fastjson 将对象转换成 json 对象。
示例:在某项目中,有一处 debug 级别的日志信息需要记录服务调用方的请求参数,因此,对 ProductQueryRequest 对象实例重写了 toString 方法,以获取完整的对象信息。
// 采用 slf4j 中占位符输出形式记录 debug 信息
logger.debug("query request: {}", productQueryRequest);
// 其中 ProductQueryRequest 对象重写了 toString 方法
@Override
public String toString() {
return "ProductQueryRequest{" +
"queryOption=" + queryOption +
", productIds=" + productIds +
", MemberId=" + MemberId +
'}';
}
- 日志记录如何分类
日志分类建议从功能上分为监控日志、统计日志、访问日志。
- 监控日志
这里的监控日志不包括统计信息,当然统计信息和访问信息均可以配置为监控信息。监控日志是开发人员需要重点关注的,因为监控日志直接关系到系统的稳定性和运维难度。典型的监控日志有请求入口和出口;外部服务调用和返回;资源消耗操作,如读写文件等;容错行为,如云硬盘的副本修复操作; 程序异常,如数据库无法连接;后台操作,定期执行删除的线程;启动、关闭、配置加载等。
- 统计日志
用户访问统计,如用户 IP,上传下载的数据量,请求 qps 情况,请求 rt 等。统计日志对格式需要严格要求,以便统计。实践中,应针对具体的日志分析平台来设计日志格式,便于对数据进行统计分析。
- 访问日志
该类日志一般在 nginx 层直接记录,如应用的 access.log,数据格式也基本统一。也可以使用相关日志分析平台来对访问日志进行统计分析。
- 日志级别如何判断
在实践中,常用的日志级别有 debug、info、warn、error 四个级别,那么应如何具体判断日志的归属级别呢?
- error
记录较重要的错误信息(注:参数检查不通过这种不是 error)。通常情况下,exception 的出现均可以认为是 error 级别的。比如查询用户信息服务获取用户信息失败的,读取文件信息返回 IOException 的,功能模块执行异常的等。
- warn
记录较重要的提示信息,如请求参数校验不通过、部分不重要的异常、非正常的条件分支(业务流程预期不符)、请求服务获取的结果为空的(潜在的风险)等。
- info
记录可用于业务数据统计、监控、定位一般问题的信息,如系统状态变化日志,业务流程的核心处理、关键动作,业务流程的状态变化。
- debug
记录调试信息,如 request/response。通常,在开发中和上线前期 debug 日志才会打开,随着系统稳定会关闭 debug 开关,只有当出现棘手的问题时才会根据需要开启。
- 日志数据如何监控
通过对日志中的关键字进行监控,可以及时发现系统故障并报警,对系统运维至关重要。服务的监控和报警是一个很大的话题,本节只介绍日志监控报警需要注意的一些问题:
- 非必要,不报警,只有需要运维马上处理的错误才需要发送报警。这样做的原因是避免长期的报警骚扰让运维人员对报警不再敏感,最后变成“狼来了”的故事。
- 明确报警关键字,例如用 ERROR 作为报警的关键字,而不是各种各样的复杂规则。这样做的原因是日志监控本质上是不断地进行字符串匹配操作,如果规则太多太复杂,就可能对线上服务产生影响。
- 对于一些预警操作,例如某个服务需要重试多次才能成功,或者某个用户的配额快用完等,可以通过每天一封报警邮件的方式来反馈。
- 每一次系统出现故障,都需要及时检查日志报警是否灵敏,日志报警的描述是否准确等,不断优化日志报警。
- 日志文件的大小
日志文件不宜过大,过大的日志文件会降低日志监控、问题定位的效率。因此需要进行日志文件的切分,具体而言,按天来分割还是按照小时分割,可以根据日志量来决定,原则就是方便开发或运维人员能快速查找日志。如下配置所示,日志文件大小定义为 20M,按天来做文件分割,并保留最近 15 天的数据。
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<fileNamePattern>${LOG_FILE}.%d{yyyy-MM-dd}.%i.log</fileNamePattern>
<maxHistory>15</maxHistory>
<maxFileSize>20MB</maxFileSize>
<totalSizeCap>20GB</totalSizeCap>
</rollingPolicy>
为了防止日志文件将整个磁盘空间占满,需要定期对日志文件进行删除。例如,在收到磁盘报警时,可以将一周以前的日志文件删除或者转储。在实践中,日志转储/删除应实现自动化,当系统监控发现磁盘空间使用率超过设定的阈值时,便根据日志文件名标注的日期进行转储/删除。
明天本号将推出本系列下篇,承接上、中两篇,介绍几种日志使用示例及常见报错,欢迎大家继续关注。
相关推荐
- 自己动手写Android数据库框架_android开发数据库搭建
-
http://blog.csdn.net/feiduclear_up/article/details/50557590推荐理由关于Android数据库操作,由于每次都要自己写数据库操作,每次还得去...
- 谷歌开源大模型评测工具LMEval,打通谷歌、OpenAI、Anthropic
-
智东西编译|金碧辉编辑|程茜智东西5月28日消息,据科技媒体TheDecoder5月26日报道,当天,谷歌正式发布开源大模型评测框架LMEval,支持对GPT-4o、Claude3.7...
- 工信部:着力推动大模型算法、框架等基础性原创性的技术突破
-
工信部新闻发言人今日在发布会上表示,下一步,我们将坚持突出重点领域,大力推动制造业数字化转型,推动人工智能创新应用。主要从以下四个方面着力。一是夯实人工智能技术底座。通过科技创新重大项目,着力推动大模...
- 乒乓反复纠结“框架不稳定”的三个小误区
-
很多球友由于对框架的认知不清晰,往往会把“框架不稳定”当成一种心理负担,从而影响学球进度,其典型状态就是训练中有模有样,一旦进入实战,就像被捆住了手脚。通过训练和学习,结合“基本功打卡群”球友们交流发...
- 前AMD、英特尔显卡架构师Raja再战GPU,号称要全面重构堆栈
-
IT之家8月5日消息,知名GPU架构师拉贾科杜里(RajaKoduri)此前曾先后在AMD和英特尔的显卡部门担任要职。而在今日,由Raja创立的GPU软件与IP初创企...
- 三种必须掌握的嵌入式开发程序架构
-
前言在嵌入式软件开发,包括单片机开发中,软件架构对于开发人员是一个必须认真考虑的问题。软件架构对于系统整体的稳定性和可靠性是非常重要的,一个合适的软件架构不仅结构清晰,并且便于开发。我相...
- 怪不得别人3秒就知道软考案例怎么做能50+
-
软考高级统一合格标准必须三科都达到45分,案例分析也一直是考生头疼的一门,但是掌握到得分点,案例能不能50+还不是你们说了算吗?今天就结合架构案例考点,分享实用的备考攻略~一、吃透考点,搭建知识框架从...
- UML统一建模常用图有哪些,各自的作用是什么?一篇文章彻底讲透
-
10万+爆款解析:9大UML图实战案例,小白也能秒懂!为什么需要UML?UML(统一建模语言)是软件开发的“蓝图”,用图形化语言描述系统结构、行为和交互,让复杂需求一目了然。它能:降低沟通成本避...
- 勒索软件转向云原生架构,直指备份基础设施
-
勒索软件组织和其他网络犯罪分子正越来越多地将目标对准基于云的备份系统,对久已确立的灾难恢复方法构成了挑战。谷歌安全研究人员在一份关于云安全威胁演变的报告中警告称,随着攻击者不断改进数据窃取、身份泄露和...
- ConceptDraw DIAGRAM:释放创意,绘就高效办公新未来
-
在当今数字化时代,可视化工具已成为提升工作效率和激发创意的关键。ConceptDrawDIAGRAM,作为一款世界顶级的商业绘图软件,凭借其强大的功能和用户友好的界面,正逐渐成为众多专业人士的首选绘...
- APP 制作界面设计教程:一步到位_app界面设计模板一套
-
想让APP界面设计高效落地,无需繁琐流程,掌握“框架搭建—细节填充—体验优化”三步法,即可一步到位完成专业级设计。黄金框架搭建是基础。采用“三三制布局”:将屏幕横向三等分,纵向保留三...
- MCP 的工作原理:关键组件_mcp部件
-
以下是MCP架构的关键组件:MCP主机:像ClaudeDesktop、GitHubCopilot或旅行助手这样的AI智能体,它们希望通过MCP协议访问工具、资源等。MCP主机会...
- 软件架构_软件架构师工资一般多少
-
软件架构师自身需要是程序员,并且必须一直坚持做一线程序员。软件架构应该是能力最强的一群程序员,他们通常会在自身承接编程任务的同时,逐渐引导整个团队向一个能够最大化生产力的系统设计方向前进。软件系统的架...
- 不知不觉将手机字体调大!老花眼是因为“老了吗”?
-
现在不管是联系、交友,还是购物,都离不开手机。中老年人使用手机的时间也在逐渐加长,刷抖音、看短视频、发朋友圈……看手机的同时,人们也不得不面对“视力危机”——老花眼,习惯眯眼看、凑近看、瞪眼看,不少人...
- 8000通用汉字学习系列讲座(第046讲)
-
[表声母字]加(续)[从声汉字]伽茄泇迦枷痂袈笳嘉驾架咖贺瘸(计14字)嘉[正音]标准音读jiā。[辨形]上下结构,十四画。会意形声字,从壴从加,加也表声。注:从壴,字义与鼓乐有关;从加,字义与...
你 发表评论:
欢迎- 一周热门
- 最近发表
- 标签列表
-
- 框架图 (58)
- flask框架 (53)
- quartz框架 (51)
- abp框架 (47)
- springmvc框架 (49)
- 分布式事务框架 (65)
- scrapy框架 (56)
- shiro框架 (61)
- 定时任务框架 (56)
- java日志框架 (61)
- mfc框架 (52)
- abb框架断路器 (48)
- beego框架 (52)
- java框架spring (58)
- grpc框架 (65)
- tornado框架 (48)
- 前端框架bootstrap (54)
- orm框架有哪些 (51)
- 知识框架图 (52)
- ppt框架 (55)
- 框架图模板 (59)
- 内联框架 (52)
- cad怎么画框架 (58)
- ssm框架实现登录注册 (49)
- oracle字符串长度 (48)