当前位置:首页 > 公众号精选 > 架构师社区
[导读]程序员的工作离不开日志。日志就像一个笔记本,可以记录程序运行时的一些信息。

程序员的工作离不开日志。

日志就像一个笔记本,可以记录程序运行时的一些信息。

小记:从0到1,看我玩弄千万日志于股掌

日志文件
通过日志,我们可以做很多事情。

日志的作用

1. 记录系统和接口的使用情况,比如请求日志
2. 记录和分析用户的行为,比如网站访问日志
3. 调试程序,和控制台的作用类似,但是控制台中的内容并不会保存到文件中,而日志可以长期保存。
4. 帮助我们排查和定位错误。比如在系统抛出异常时,将异常信息记录到日志,可以事后复盘。
5. 通过分析日志还能够优化代码逻辑、提升系统性能、稳定性等。
小记:从0到1,看我玩弄千万日志于股掌
日志虽然有那么多的作用,但如果数量过多,也会让开发人员感到头疼。对于大型的系统,程序员们经常要看几千、几万行日志,常常看日志看到头晕眼花。
小记:从0到1,看我玩弄千万日志于股掌
但是,其实处理日志是有很多技巧的,下面鱼皮分享自己和日志的故事。
故事分为 7 个阶段,从看日志看到怀疑人生,再到玩弄千万日志于股掌,鱼皮都做了哪些事情?

鱼皮和日志的爱恨情仇
第一阶段 无日志
刚开始搭建新的系统时,为了图个方便,鱼皮没有给系统接入任何的日志框架,也没有记录任何日志,整个项目非常的干净丝滑。需要调试时就直接用输出函数将信息打印在控制台,出了异常就直接打印堆栈。
    
// 输出调试 System.out.println("value = " + value); // 出现异常 catch(Exception e) { e.printStackTrace(); }
真是无事一身轻,爽的不得了!
小记:从0到1,看我玩弄千万日志于股掌
可惜,好景不长。在项目上线之后,突然有一天,系统出问题了,数据查不出来了,同事找上门来了。
鱼皮笑着说:“问题不大!”
小记:从0到1,看我玩弄千万日志于股掌
然后登录服务器,进入项目目录,瞬间傻眼。
项目目录依旧干净丝滑,原来我特么根本没记日志啊!
这下好了,什么问题都查不出来。乖乖地去给项目加上日志功能吧。

第二阶段 引入日志类库
Java 语言有很多优秀的日志类库,比如 Logback、Log4j2 等,提供了很多记录和打印日志的方法,非常方便。可以直接使用其中一个类库,而无需自己实现。此处因为鱼皮的项目使用 Spring Boot 框架进行开发,直接使用其默认日志库 Logback 即可。
使用方式很简单,先添加 logback.xml 配置文件,主要配置了日志文件的存储路径和格式。Logback 框架还会自动将日志按天进行压缩,并且在一定天数后进行删除,以节约磁盘空间。最大存储天数也可以在配置文件中指定。
配置文件大概长这样:
    
<configuration scan="true" scanPeriod="60 seconds"> <include resource="org/springframework/boot/logging/logback/defaults.xml"/>
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender"> <file>logs/application.logfile> <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> <fileNamePattern>log/application-log-%d{yyyy-MM-dd}.gzfileNamePattern> <maxHistory>30maxHistory> rollingPolicy> <encoder> <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} %-5level ${PID:- } ...pattern> <charset>UTF-8charset> encoder> appender> ... configuration>
在要打印日志的类上创建一个日志对象:
Logger logger = LoggerFactory.getLogger(MyApp.class);
然后就可以使用该对象去记录日志啦:
    
catch(Exception e) { logger.error("app error", e); }
加上配置文件后,启动项目,就可以看见生成的日志文件了。欧耶,下次系统再出问题,就不怕缺乏信息来排错啦!
小记:从0到1,看我玩弄千万日志于股掌
系统运行了一个小时之后,同事又找上门来了,这次鱼皮很有底气,笑着说:“问题不大!”
小记:从0到1,看我玩弄千万日志于股掌
然后打开日志文件一看,傻眼了,有几千行日志,我怎么知道哪行日志是报错信息呢?
小记:从0到1,看我玩弄千万日志于股掌 这你能秒了我? 直接用 Linux 命令过滤出带 “ERROR” 字段的日志行就行了~
    
cat application.log | grep 'ERROR'
虽然解决了问题,但是后面每次报错,都要输一遍这个筛选命令,而且随着文件越来越大,命令执行的速度越来越慢了。
能不能把所有错误日志和正常日志区分开,放在不同的文件中呢?

第三阶段 日志分级
幸运的是,一般的日志框架都提供了日志分级存储功能,可以通过修改配置文件来实现。
修改 logback.xml 配置文件,将 ERROR(错误)级别的日志单独输出到 error.log 文件中,实现日志分级:
    
<configuration ...> <appender name="ERROR" class="ch.qos.logback.core.rolling.RollingFileAppender"> <file>logs/error.logfile> <filter class="ch.qos.logback.classic.filter.LevelFilter"> <level>ERRORlevel> <onMatch>ACCEPTonMatch> <onMismatch>DENYonMismatch> filter> <encoder> <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} %-5level ${PID:- } [%15.15thread] %-50.50logger{50} - %msg%npattern> <charset>UTF-8charset> encoder> appender> configuration>
启动项目,日志按预期分级写到了 application.log 和 error.log 两个文件。系统再出现异常时,鱼皮只需打开 error.log 文件,错误信息一览无遗!
小记:从0到1,看我玩弄千万日志于股掌
系统运行一段时间后,鱼皮上线了一个很重要的服务,记录了相当多的业务日志。虽然目前错误日志可以单独查看,但是核心服务的日志和其他服务的正常日志都堆积在 application.log 中,想要仅 查看核心服务的日志依旧要采用命令过滤的方式,比较麻烦。
小记:从0到1,看我玩弄千万日志于股掌
有没有什么办法,把核心业务的日志单独记录到一个文件中呢?

第四阶段 按类隔离
幸运的是,Logback 日志框架支持将不同的类产生的日志记录到不同的文件中,修改配置文件即可。比如将所有 RequestAOP 类产生的请求日志记录到 request.log 中:
    
<appender name="REQUEST_HANDLER" class="ch.qos.logback.core.rolling.RollingFileAppender"> <file>logs/request.logfile> <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> ... rollingPolicy> <encoder> <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} %-5level ${PID:- } [%15.15thread] %-50.50logger{50} - %msg%npattern> <charset>UTF-8charset> encoder> appender> <logger name="com.yupi.RequestAOP" level="INFO" additivity="false"> <appender-ref ref="REQUEST_HANDLER"/> logger>
启动项目,自动生成了 request.log 文件,打开这个文件,就可以查看所有的请求日志,可以用于流控分析等等,真爽死了!
小记:从0到1,看我玩弄千万日志于股掌
后来,随着系统的访问量越来越大,单台服务器已经不能满足对并发的需求,因此鱼皮又加了三台机器,共同提供服务。
小记:从0到1,看我玩弄千万日志于股掌
有一天,系统又出问题了,同事找上门来,鱼皮心想:信不信分分钟给你解决 bug!
小记:从0到1,看我玩弄千万日志于股掌
一顿操作猛如虎,登录一台服务器查看日志,结果错误日志空空如也,比鱼皮的兜儿都干净。
奇怪了,怎么找不到错误信息?
对啊,现在有四台机器,请求可能落在了其他机器上,因此错误日志也可能在别的机器上!
小记:从0到1,看我玩弄千万日志于股掌
哎,没办法,一台一台登录服务器去找错误信息吧。
其实四台机器还能忍,但是后来随着并发量的增大,鱼皮负责的系统已经有十台机器了,每次查看日志要依次登录十台机器去找!而且单个日志数据的量已经达到几十万行,无论怎么切分看起来都太累了。
哦,乔治,这太难受了!有没有什么办法,能让我在一个地方集中看日志啊!
小记:从0到1,看我玩弄千万日志于股掌
要不直接把日志记录到数据库中?
不行不行,日志数据量太大了,数据库肯定存不下。而且写入数据库的速度受到网络传输等限制,比较缓慢。
怎么办啊?算了,先睡一觉。
小记:从0到1,看我玩弄千万日志于股掌
第五阶段 日志上报与集中式管理
“嘿,少年,你想要力量么?”
“废话,谁不想要!”
“听说过 ELK 么?他会指引你前进的方向。”
鱼皮从梦中惊醒,对啊,可以用 ELK 搭建一个分布式日志收集系统啊!
小记:从0到1,看我玩弄千万日志于股掌
ELK 是 Elasticsearch、Logstash 和 Kibana 的简称,不是单独的一个软件,而是一整套问题的解决方案
Elasticsearch(简称 ES)是全文搜索引擎,能够对海量数据进行存储和高效的搜索。
小记:从0到1,看我玩弄千万日志于股掌
Logstash 是一个数据管道,能够从各种数据源(比如 MySQL 数据库)收集数据,将数据从一处传输到另一处,并加以解析和转换。
小记:从0到1,看我玩弄千万日志于股掌
Kibana 是数据可视化平台,可以将 Elasticsearch 中存储的数据进行展示。在 Kibana 上,我们不仅可以看到所有原始的日志信息,还能够自定义各种精美直观的可视化图表。
小记:从0到1,看我玩弄千万日志于股掌

通常使用 Logstash 统一收集各个机器上的数据,并传输至 Elasticsearch 进行存储,最后通过 Kibana 进行数据展示,之后就可以利用 Kibana 轻松地查看和分析所有的数据了。
小记:从0到1,看我玩弄千万日志于股掌
既然可以解决问题,那就接入 ELK 吧~
但是使用 ELK 相当于为系统引入了三个新组件,考虑到系统使用的组件越多,复杂度越高,就越难维护;而且 Logstash 比较重,对 CPU 和内存的占用较高。因此,鱼皮灵机一动,干脆舍弃掉 Logstash,直接将 Elasticsearch 当成数据库来使用。
先在 Spring Boot 中整合 Elasticsearch,然后将日志数据通过依赖包提供的 API 接口存储到 Elasticsearch,最后接入 Kibana 进行展示。
Maven 引入依赖:
    
<dependency> <groupId>org.springframework.bootgroupId> <artifactId>spring-boot-starter-data-elasticsearchartifactId> <version>2.3.4.RELEASEversion> dependency>
访问 ES 的接口:
    
@Repository public interface UserRepository extends ElasticsearchRepository<HouseIndexTemplate, Long> {
}
想法是美好的,现实却是贼特么残酷的。
虽然 Spring Boot 接入 Elasticsearch 的确很方便,但是要把整个项目中的记日志代码全部替换成写入 ES 的代码,对项目的改动和侵入性太大了。而且将日志存入 ES 的耗时远远大于原来异步写入文件的耗时,并发量很大时,偶尔出现日志写入失败的情况。因此改代码改到一半时,鱼皮就抓狂放弃了,直接把改了的代码全部还原。
小记:从0到1,看我玩弄千万日志于股掌
鱼皮再次陷入沉思,有没有一种方式,可以在不改动一行代码的情况下,将日志写入 ES 呢?

第六阶段 日志代
如果不改动任何代码,每台机器产生的日志仍然是独立记录到当前机器的日志文件中的,想要通过一个界面集中查看各机器上的日志非常麻烦。
那如果把日志文件中的数据自动同步到 ES 上,不就能通过 Kibana 方便地查看了么!
谁来做同步这件事呢?难道要我自己写个定时任务程序把日志文件上传到 ES 上?如果是那样,我还不如继续改原来项目的代码。
小记:从0到1,看我玩弄千万日志于股掌
能不能找个代理来帮我做这件事呢?
就像我们每天丢辣鸡一样,把辣鸡丢到小区门口的辣鸡桶就行了,然后辣鸡车会帮我们把辣鸡运送至辣鸡站集中处理。
我们的日志文件相当于辣鸡,代理就相当于辣鸡车,而 ES 就相当于辣鸡站。
通过百度,发现 ELK 早就升级为 ElasticStack 了,除了上面说的三大组件外,还多了一个 Beats。
Beats 是轻量级数据采集器,针对不同的数据类型提供了不同的组件。
小记:从0到1,看我玩弄千万日志于股掌
要将日志文件数据上传到 ES 进行存储,可以使用 Filebeat。Filebeat 是轻量型日志采集器,其提供了一种轻量型方法,用于转发和汇总日志与文件,让我们轻松面对成百上千、甚至成千上万的服务器、虚拟机和容器生成的日志。
Filebeat 就相当于一个代理(agent),可以帮助收集各个机器上的日志,然后传输给 Logstash 进行处理或者直接传输到 Elasticsearch 进行存储。这样就完全不用修改项目的代码!
ElasticStack 整体架构如下:
小记:从0到1,看我玩弄千万日志于股掌

那怎么使用 Filebeat 呢?
其实非常简单,直接将 Filebeat 安装到日志文件所在的服务器上,然后在其配置文件中定义输入(要采集的日志文件路径)和输出(要将采集到的数据发送到哪里)即可。比如在下面的配置中,会采集 system 日志并传输给 Logstash:
    
filebeat.inputs: - type: log paths: - /var/log/system.log
output.logstash: hosts: ["127.0.0.1:5044"]
搞定,这下真是爽死了! 经几千行日志就能将我淹没,不知所措。而现在,只需要打开 Kibana 控制台, 动动手指,就 能轻松地查看和分析几十万、几百万的日志。
小记:从0到1,看我玩弄千万日志于股掌
感觉自己就像一个大将军,这些日志是我统治的小兵,都得乖乖听我号令,好不痛快!
小记:从0到1,看我玩弄千万日志于股掌

第七阶段 完善日志架构
利用 ElasticStack,已经能够轻松地集中管理海量的日志,而且 Elasticsearch 支持水平扩容,可以应对日志量级的持续增大,存个千万条数据完全没有问题。
但是,当每秒产生的日志量过多时,ElasticStack 并不是无敌的,虽然 Filebeat、Elasticsearch、Kibana 都很强劲,但往往 Logstash 是那阿喀琉斯之踵(或者三娃的屁股)!
小记:从0到1,看我玩弄千万日志于股掌
因为 Logstash 要同时接受多个 Filebeat 采集的日志,机器越多,部署的 Filebeat 也就越多,Logstash 的压力就会越大。虽然也可以像扩容 ES 一样增加 Logstash 的节点数,但是并不能从根本上解决问题,当日志量级增大到一定程度时,不仅是 Logstash,连 ES 集群都有可能撑不住!
因此,我们需要接入一些中间件来进行缓冲,首选的可靠且高性能的消息队列 Kafka(依赖分布式协调工具 Zookeeper)。
最终,完善的分布式日志收集系统架构如下:

小记:从0到1,看我玩弄千万日志于股掌

至此,鱼皮终于将千万日志玩弄于股掌,这种感觉真的是太爽了。
小记:从0到1,看我玩弄千万日志于股掌
如果你也正在被日志折磨,一定要试着搭建一套完善的日志系统。

最后分享自己记录日志的经验:
1. 不要过度依赖日志,什么都记,日志应当简洁明晰,具有实际价值。
2. 在保证可理解的同时适当减少日志的长度,比如把 this is an apple 简化为 apple。
3. 将日志进行分级和分类,仅在开发和测试环境输出 DEBUG 级别日志,不要在生产环境中使用。
4. 统一日志的格式,便于后续处理分析,通常在日志框架配置即可。
5. 不要把日志当成存储数据的工具!注意日志信息中不能出现敏感信息,也不要对外公开!

鱼皮从 0 到 1,经历了七个阶段,成功地玩弄千万日志于股掌。其实,无论是学习还是实际应用,我们都需要有这种持续实践、探索和优化的精神
会当凌绝顶,一览众山小。

特别推荐一个分享架构+算法的优质内容,还没关注的小伙伴,可以长按关注一下:

小记:从0到1,看我玩弄千万日志于股掌

小记:从0到1,看我玩弄千万日志于股掌

小记:从0到1,看我玩弄千万日志于股掌

长按订阅更多精彩▼

小记:从0到1,看我玩弄千万日志于股掌

如有收获,点个在看,诚挚感谢

免责声明:本文内容由21ic获得授权后发布,版权归原作者所有,本平台仅提供信息存储服务。文章仅代表作者个人观点,不代表本平台立场,如有问题,请联系我们,谢谢!

本站声明: 本文章由作者或相关机构授权发布,目的在于传递更多信息,并不代表本站赞同其观点,本站亦不保证或承诺内容真实性等。需要转载请联系该专栏作者,如若文章内容侵犯您的权益,请及时联系本站删除。
换一批
延伸阅读

9月2日消息,不造车的华为或将催生出更大的独角兽公司,随着阿维塔和赛力斯的入局,华为引望愈发显得引人瞩目。

关键字: 阿维塔 塞力斯 华为

加利福尼亚州圣克拉拉县2024年8月30日 /美通社/ -- 数字化转型技术解决方案公司Trianz今天宣布,该公司与Amazon Web Services (AWS)签订了...

关键字: AWS AN BSP 数字化

伦敦2024年8月29日 /美通社/ -- 英国汽车技术公司SODA.Auto推出其旗舰产品SODA V,这是全球首款涵盖汽车工程师从创意到认证的所有需求的工具,可用于创建软件定义汽车。 SODA V工具的开发耗时1.5...

关键字: 汽车 人工智能 智能驱动 BSP

北京2024年8月28日 /美通社/ -- 越来越多用户希望企业业务能7×24不间断运行,同时企业却面临越来越多业务中断的风险,如企业系统复杂性的增加,频繁的功能更新和发布等。如何确保业务连续性,提升韧性,成...

关键字: 亚马逊 解密 控制平面 BSP

8月30日消息,据媒体报道,腾讯和网易近期正在缩减他们对日本游戏市场的投资。

关键字: 腾讯 编码器 CPU

8月28日消息,今天上午,2024中国国际大数据产业博览会开幕式在贵阳举行,华为董事、质量流程IT总裁陶景文发表了演讲。

关键字: 华为 12nm EDA 半导体

8月28日消息,在2024中国国际大数据产业博览会上,华为常务董事、华为云CEO张平安发表演讲称,数字世界的话语权最终是由生态的繁荣决定的。

关键字: 华为 12nm 手机 卫星通信

要点: 有效应对环境变化,经营业绩稳中有升 落实提质增效举措,毛利润率延续升势 战略布局成效显著,战新业务引领增长 以科技创新为引领,提升企业核心竞争力 坚持高质量发展策略,塑强核心竞争优势...

关键字: 通信 BSP 电信运营商 数字经济

北京2024年8月27日 /美通社/ -- 8月21日,由中央广播电视总台与中国电影电视技术学会联合牵头组建的NVI技术创新联盟在BIRTV2024超高清全产业链发展研讨会上宣布正式成立。 活动现场 NVI技术创新联...

关键字: VI 传输协议 音频 BSP

北京2024年8月27日 /美通社/ -- 在8月23日举办的2024年长三角生态绿色一体化发展示范区联合招商会上,软通动力信息技术(集团)股份有限公司(以下简称"软通动力")与长三角投资(上海)有限...

关键字: BSP 信息技术
关闭
关闭