當前位置:首頁 > 公眾號精選 > 架構師社區(qū)
[導讀]程序員的工作離不開日志。日志就像一個筆記本,可以記錄程序運行時的一些信息。

程序員的工作離不開日志。

日志就像一個筆記本,可以記錄程序運行時的一些信息。

小記:從0到1,看我玩弄千萬日志于股掌

日志文件
通過日志,我們可以做很多事情。

日志的作用

1. 記錄系統(tǒng)和接口的使用情況,比如請求日志
2. 記錄和分析用戶的行為,比如網站訪問日志
3. 調試程序,和控制臺的作用類似,但是控制臺中的內容并不會保存到文件中,而日志可以長期保存。
4. 幫助我們排查和定位錯誤。比如在系統(tǒng)拋出異常時,將異常信息記錄到日志,可以事后復盤。
5. 通過分析日志還能夠優(yōu)化代碼邏輯、提升系統(tǒng)性能、穩(wěn)定性等。
小記:從0到1,看我玩弄千萬日志于股掌
日志雖然有那么多的作用,但如果數(shù)量過多,也會讓開發(fā)人員感到頭疼。對于大型的系統(tǒng),程序員們經常要看幾千、幾萬行日志,常??慈罩究吹筋^暈眼花。
小記:從0到1,看我玩弄千萬日志于股掌
但是,其實處理日志是有很多技巧的,下面魚皮分享自己和日志的故事。
故事分為 7 個階段,從看日志看到懷疑人生,再到玩弄千萬日志于股掌,魚皮都做了哪些事情?

魚皮和日志的愛恨情仇
第一階段 無日志
剛開始搭建新的系統(tǒng)時,為了圖個方便,魚皮沒有給系統(tǒng)接入任何的日志框架,也沒有記錄任何日志,整個項目非常的干凈絲滑。需要調試時就直接用輸出函數(shù)將信息打印在控制臺,出了異常就直接打印堆棧。
    
// 輸出調試 System.out.println("value = " + value); // 出現(xiàn)異常 catch(Exception e) { e.printStackTrace(); }
真是無事一身輕,爽的不得了!
小記:從0到1,看我玩弄千萬日志于股掌
可惜,好景不長。在項目上線之后,突然有一天,系統(tǒng)出問題了,數(shù)據(jù)查不出來了,同事找上門來了。
魚皮笑著說:“問題不大!”
小記:從0到1,看我玩弄千萬日志于股掌
然后登錄服務器,進入項目目錄,瞬間傻眼。
項目目錄依舊干凈絲滑,原來我特么根本沒記日志?。?/span>
這下好了,什么問題都查不出來。乖乖地去給項目加上日志功能吧。

第二階段 引入日志類庫
Java 語言有很多優(yōu)秀的日志類庫,比如 Logback、Log4j2 等,提供了很多記錄和打印日志的方法,非常方便。可以直接使用其中一個類庫,而無需自己實現(xiàn)。此處因為魚皮的項目使用 Spring Boot 框架進行開發(fā),直接使用其默認日志庫 Logback 即可。
使用方式很簡單,先添加 logback.xml 配置文件,主要配置了日志文件的存儲路徑和格式。Logback 框架還會自動將日志按天進行壓縮,并且在一定天數(shù)后進行刪除,以節(jié)約磁盤空間。最大存儲天數(shù)也可以在配置文件中指定。
配置文件大概長這樣:
    
<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>
在要打印日志的類上創(chuàng)建一個日志對象:
Logger logger = LoggerFactory.getLogger(MyApp.class);
然后就可以使用該對象去記錄日志啦:
    
catch(Exception e) { logger.error("app error", e); }
加上配置文件后,啟動項目,就可以看見生成的日志文件了。歐耶,下次系統(tǒng)再出問題,就不怕缺乏信息來排錯啦!
小記:從0到1,看我玩弄千萬日志于股掌
系統(tǒng)運行了一個小時之后,同事又找上門來了,這次魚皮很有底氣,笑著說:“問題不大!”
小記:從0到1,看我玩弄千萬日志于股掌
然后打開日志文件一看,傻眼了,有幾千行日志,我怎么知道哪行日志是報錯信息呢?
小記:從0到1,看我玩弄千萬日志于股掌 這你能秒了我? 直接用 Linux 命令過濾出帶 “ERROR” 字段的日志行就行了~
    
cat application.log | grep 'ERROR'
雖然解決了問題,但是后面每次報錯,都要輸一遍這個篩選命令,而且隨著文件越來越大,命令執(zhí)行的速度越來越慢了。
能不能把所有錯誤日志和正常日志區(qū)分開,放在不同的文件中呢?

第三階段 日志分級
幸運的是,一般的日志框架都提供了日志分級存儲功能,可以通過修改配置文件來實現(xiàn)。
修改 logback.xml 配置文件,將 ERROR(錯誤)級別的日志單獨輸出到 error.log 文件中,實現(xiàn)日志分級:
    
<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 兩個文件。系統(tǒng)再出現(xiàn)異常時,魚皮只需打開 error.log 文件,錯誤信息一覽無遺!
小記:從0到1,看我玩弄千萬日志于股掌
系統(tǒng)運行一段時間后,魚皮上線了一個很重要的服務,記錄了相當多的業(yè)務日志。雖然目前錯誤日志可以單獨查看,但是核心服務的日志和其他服務的正常日志都堆積在 application.log 中,想要僅 查看核心服務的日志依舊要采用命令過濾的方式,比較麻煩。
小記:從0到1,看我玩弄千萬日志于股掌
有沒有什么辦法,把核心業(yè)務的日志單獨記錄到一個文件中呢?

第四階段 按類隔離
幸運的是,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,看我玩弄千萬日志于股掌
后來,隨著系統(tǒng)的訪問量越來越大,單臺服務器已經不能滿足對并發(fā)的需求,因此魚皮又加了三臺機器,共同提供服務。
小記:從0到1,看我玩弄千萬日志于股掌
有一天,系統(tǒng)又出問題了,同事找上門來,魚皮心想:信不信分分鐘給你解決 bug!
小記:從0到1,看我玩弄千萬日志于股掌
一頓操作猛如虎,登錄一臺服務器查看日志,結果錯誤日志空空如也,比魚皮的兜兒都干凈。
奇怪了,怎么找不到錯誤信息?
對啊,現(xiàn)在有四臺機器,請求可能落在了其他機器上,因此錯誤日志也可能在別的機器上!
小記:從0到1,看我玩弄千萬日志于股掌
哎,沒辦法,一臺一臺登錄服務器去找錯誤信息吧。
其實四臺機器還能忍,但是后來隨著并發(fā)量的增大,魚皮負責的系統(tǒng)已經有十臺機器了,每次查看日志要依次登錄十臺機器去找!而且單個日志數(shù)據(jù)的量已經達到幾十萬行,無論怎么切分看起來都太累了。
哦,喬治,這太難受了!有沒有什么辦法,能讓我在一個地方集中看日志?。?/span>
小記:從0到1,看我玩弄千萬日志于股掌
要不直接把日志記錄到數(shù)據(jù)庫中?
不行不行,日志數(shù)據(jù)量太大了,數(shù)據(jù)庫肯定存不下。而且寫入數(shù)據(jù)庫的速度受到網絡傳輸?shù)认拗疲容^緩慢。
怎么辦啊?算了,先睡一覺。
小記:從0到1,看我玩弄千萬日志于股掌
第五階段 日志上報與集中式管理
“嘿,少年,你想要力量么?”
“廢話,誰不想要!”
“聽說過 ELK 么?他會指引你前進的方向?!?/span>
魚皮從夢中驚醒,對啊,可以用 ELK 搭建一個分布式日志收集系統(tǒng)?。?/span>
小記:從0到1,看我玩弄千萬日志于股掌
ELK 是 Elasticsearch、Logstash 和 Kibana 的簡稱,不是單獨的一個軟件,而是一整套問題的解決方案
Elasticsearch(簡稱 ES)是全文搜索引擎,能夠對海量數(shù)據(jù)進行存儲和高效的搜索。
小記:從0到1,看我玩弄千萬日志于股掌
Logstash 是一個數(shù)據(jù)管道,能夠從各種數(shù)據(jù)源(比如 MySQL 數(shù)據(jù)庫)收集數(shù)據(jù),將數(shù)據(jù)從一處傳輸?shù)搅硪惶帲⒓右越馕龊娃D換。
小記:從0到1,看我玩弄千萬日志于股掌
Kibana 是數(shù)據(jù)可視化平臺,可以將 Elasticsearch 中存儲的數(shù)據(jù)進行展示。在 Kibana 上,我們不僅可以看到所有原始的日志信息,還能夠自定義各種精美直觀的可視化圖表。
小記:從0到1,看我玩弄千萬日志于股掌

通常使用 Logstash 統(tǒng)一收集各個機器上的數(shù)據(jù),并傳輸至 Elasticsearch 進行存儲,最后通過 Kibana 進行數(shù)據(jù)展示,之后就可以利用 Kibana 輕松地查看和分析所有的數(shù)據(jù)了。
小記:從0到1,看我玩弄千萬日志于股掌
既然可以解決問題,那就接入 ELK 吧~
但是使用 ELK 相當于為系統(tǒng)引入了三個新組件,考慮到系統(tǒng)使用的組件越多,復雜度越高,就越難維護;而且 Logstash 比較重,對 CPU 和內存的占用較高。因此,魚皮靈機一動,干脆舍棄掉 Logstash,直接將 Elasticsearch 當成數(shù)據(jù)庫來使用。
先在 Spring Boot 中整合 Elasticsearch,然后將日志數(shù)據(jù)通過依賴包提供的 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> {
}
想法是美好的,現(xiàn)實卻是賊特么殘酷的。
雖然 Spring Boot 接入 Elasticsearch 的確很方便,但是要把整個項目中的記日志代碼全部替換成寫入 ES 的代碼,對項目的改動和侵入性太大了。而且將日志存入 ES 的耗時遠遠大于原來異步寫入文件的耗時,并發(fā)量很大時,偶爾出現(xiàn)日志寫入失敗的情況。因此改代碼改到一半時,魚皮就抓狂放棄了,直接把改了的代碼全部還原。
小記:從0到1,看我玩弄千萬日志于股掌
魚皮再次陷入沉思,有沒有一種方式,可以在不改動一行代碼的情況下,將日志寫入 ES 呢?

第六階段 日志代
如果不改動任何代碼,每臺機器產生的日志仍然是獨立記錄到當前機器的日志文件中的,想要通過一個界面集中查看各機器上的日志非常麻煩。
那如果把日志文件中的數(shù)據(jù)自動同步到 ES 上,不就能通過 Kibana 方便地查看了么!
誰來做同步這件事呢?難道要我自己寫個定時任務程序把日志文件上傳到 ES 上?如果是那樣,我還不如繼續(xù)改原來項目的代碼。
小記:從0到1,看我玩弄千萬日志于股掌
能不能找個代理來幫我做這件事呢?
就像我們每天丟辣雞一樣,把辣雞丟到小區(qū)門口的辣雞桶就行了,然后辣雞車會幫我們把辣雞運送至辣雞站集中處理。
我們的日志文件相當于辣雞,代理就相當于辣雞車,而 ES 就相當于辣雞站。
通過百度,發(fā)現(xiàn) ELK 早就升級為 ElasticStack 了,除了上面說的三大組件外,還多了一個 Beats。
Beats 是輕量級數(shù)據(jù)采集器,針對不同的數(shù)據(jù)類型提供了不同的組件。
小記:從0到1,看我玩弄千萬日志于股掌
要將日志文件數(shù)據(jù)上傳到 ES 進行存儲,可以使用 Filebeat。Filebeat 是輕量型日志采集器,其提供了一種輕量型方法,用于轉發(fā)和匯總日志與文件,讓我們輕松面對成百上千、甚至成千上萬的服務器、虛擬機和容器生成的日志。
Filebeat 就相當于一個代理(agent),可以幫助收集各個機器上的日志,然后傳輸給 Logstash 進行處理或者直接傳輸?shù)?Elasticsearch 進行存儲。這樣就完全不用修改項目的代碼!
ElasticStack 整體架構如下:
小記:從0到1,看我玩弄千萬日志于股掌

那怎么使用 Filebeat 呢?
其實非常簡單,直接將 Filebeat 安裝到日志文件所在的服務器上,然后在其配置文件中定義輸入(要采集的日志文件路徑)和輸出(要將采集到的數(shù)據(jù)發(fā)送到哪里)即可。比如在下面的配置中,會采集 system 日志并傳輸給 Logstash:
    
filebeat.inputs: - type: log paths: - /var/log/system.log
output.logstash: hosts: ["127.0.0.1:5044"]
搞定,這下真是爽死了! 經幾千行日志就能將我淹沒,不知所措。而現(xiàn)在,只需要打開 Kibana 控制臺, 動動手指,就 能輕松地查看和分析幾十萬、幾百萬的日志。
小記:從0到1,看我玩弄千萬日志于股掌
感覺自己就像一個大將軍,這些日志是我統(tǒng)治的小兵,都得乖乖聽我號令,好不痛快!
小記:從0到1,看我玩弄千萬日志于股掌

第七階段?完善日志架構
利用 ElasticStack,已經能夠輕松地集中管理海量的日志,而且 Elasticsearch 支持水平擴容,可以應對日志量級的持續(xù)增大,存?zhèn)€千萬條數(shù)據(jù)完全沒有問題。
但是,當每秒產生的日志量過多時,ElasticStack 并不是無敵的,雖然 Filebeat、Elasticsearch、Kibana 都很強勁,但往往 Logstash 是那阿喀琉斯之踵(或者三娃的屁股)!
小記:從0到1,看我玩弄千萬日志于股掌
因為 Logstash 要同時接受多個 Filebeat 采集的日志,機器越多,部署的 Filebeat 也就越多,Logstash 的壓力就會越大。雖然也可以像擴容 ES 一樣增加 Logstash 的節(jié)點數(shù),但是并不能從根本上解決問題,當日志量級增大到一定程度時,不僅是 Logstash,連 ES 集群都有可能撐不?。?/span>
因此,我們需要接入一些中間件來進行緩沖,首選的可靠且高性能的消息隊列 Kafka(依賴分布式協(xié)調工具 Zookeeper)。
最終,完善的分布式日志收集系統(tǒng)架構如下:

小記:從0到1,看我玩弄千萬日志于股掌

至此,魚皮終于將千萬日志玩弄于股掌,這種感覺真的是太爽了。
小記:從0到1,看我玩弄千萬日志于股掌
如果你也正在被日志折磨,一定要試著搭建一套完善的日志系統(tǒng)。

最后分享自己記錄日志的經驗:
1. 不要過度依賴日志,什么都記,日志應當簡潔明晰,具有實際價值。
2. 在保證可理解的同時適當減少日志的長度,比如把 this is an apple 簡化為 apple。
3. 將日志進行分級和分類,僅在開發(fā)和測試環(huán)境輸出 DEBUG 級別日志,不要在生產環(huán)境中使用。
4. 統(tǒng)一日志的格式,便于后續(xù)處理分析,通常在日志框架配置即可。
5. 不要把日志當成存儲數(shù)據(jù)的工具!注意日志信息中不能出現(xiàn)敏感信息,也不要對外公開!

魚皮從 0 到 1,經歷了七個階段,成功地玩弄千萬日志于股掌。其實,無論是學習還是實際應用,我們都需要有這種持續(xù)實踐、探索和優(yōu)化的精神。
會當凌絕頂,一覽眾山小。

特別推薦一個分享架構+算法的優(yōu)質內容,還沒關注的小伙伴,可以長按關注一下:

小記:從0到1,看我玩弄千萬日志于股掌

小記:從0到1,看我玩弄千萬日志于股掌

小記:從0到1,看我玩弄千萬日志于股掌

長按訂閱更多精彩▼

小記:從0到1,看我玩弄千萬日志于股掌

如有收獲,點個在看,誠摯感謝

免責聲明:本文內容由21ic獲得授權后發(fā)布,版權歸原作者所有,本平臺僅提供信息存儲服務。文章僅代表作者個人觀點,不代表本平臺立場,如有問題,請聯(lián)系我們,謝謝!

本站聲明: 本文章由作者或相關機構授權發(fā)布,目的在于傳遞更多信息,并不代表本站贊同其觀點,本站亦不保證或承諾內容真實性等。需要轉載請聯(lián)系該專欄作者,如若文章內容侵犯您的權益,請及時聯(lián)系本站刪除。
換一批
延伸閱讀

9月2日消息,不造車的華為或將催生出更大的獨角獸公司,隨著阿維塔和賽力斯的入局,華為引望愈發(fā)顯得引人矚目。

關鍵字: 阿維塔 塞力斯 華為

加利福尼亞州圣克拉拉縣2024年8月30日 /美通社/ -- 數(shù)字化轉型技術解決方案公司Trianz今天宣布,該公司與Amazon Web Services (AWS)簽訂了...

關鍵字: AWS AN BSP 數(shù)字化

倫敦2024年8月29日 /美通社/ -- 英國汽車技術公司SODA.Auto推出其旗艦產品SODA V,這是全球首款涵蓋汽車工程師從創(chuàng)意到認證的所有需求的工具,可用于創(chuàng)建軟件定義汽車。 SODA V工具的開發(fā)耗時1.5...

關鍵字: 汽車 人工智能 智能驅動 BSP

北京2024年8月28日 /美通社/ -- 越來越多用戶希望企業(yè)業(yè)務能7×24不間斷運行,同時企業(yè)卻面臨越來越多業(yè)務中斷的風險,如企業(yè)系統(tǒng)復雜性的增加,頻繁的功能更新和發(fā)布等。如何確保業(yè)務連續(xù)性,提升韌性,成...

關鍵字: 亞馬遜 解密 控制平面 BSP

8月30日消息,據(jù)媒體報道,騰訊和網易近期正在縮減他們對日本游戲市場的投資。

關鍵字: 騰訊 編碼器 CPU

8月28日消息,今天上午,2024中國國際大數(shù)據(jù)產業(yè)博覽會開幕式在貴陽舉行,華為董事、質量流程IT總裁陶景文發(fā)表了演講。

關鍵字: 華為 12nm EDA 半導體

8月28日消息,在2024中國國際大數(shù)據(jù)產業(yè)博覽會上,華為常務董事、華為云CEO張平安發(fā)表演講稱,數(shù)字世界的話語權最終是由生態(tài)的繁榮決定的。

關鍵字: 華為 12nm 手機 衛(wèi)星通信

要點: 有效應對環(huán)境變化,經營業(yè)績穩(wěn)中有升 落實提質增效舉措,毛利潤率延續(xù)升勢 戰(zhàn)略布局成效顯著,戰(zhàn)新業(yè)務引領增長 以科技創(chuàng)新為引領,提升企業(yè)核心競爭力 堅持高質量發(fā)展策略,塑強核心競爭優(yōu)勢...

關鍵字: 通信 BSP 電信運營商 數(shù)字經濟

北京2024年8月27日 /美通社/ -- 8月21日,由中央廣播電視總臺與中國電影電視技術學會聯(lián)合牽頭組建的NVI技術創(chuàng)新聯(lián)盟在BIRTV2024超高清全產業(yè)鏈發(fā)展研討會上宣布正式成立。 活動現(xiàn)場 NVI技術創(chuàng)新聯(lián)...

關鍵字: VI 傳輸協(xié)議 音頻 BSP

北京2024年8月27日 /美通社/ -- 在8月23日舉辦的2024年長三角生態(tài)綠色一體化發(fā)展示范區(qū)聯(lián)合招商會上,軟通動力信息技術(集團)股份有限公司(以下簡稱"軟通動力")與長三角投資(上海)有限...

關鍵字: BSP 信息技術
關閉
關閉