軟體打log的一些心得

2021-08-07 18:35:46 字數 3937 閱讀 8505

本文適用範圍:linux系統

使用語言:c/c++

打log的原則:

1. 異常分支或錯誤處理一定要打log

2. 重大操作時一定要打log,下面打log場景會講述

log格式的原則:

1. 時間戳必須有,最好能夠精確到微秒。精確到秒的時間戳,相信很多人都熟悉,這能夠確認問題的時間和系統uptime的對比,能夠進一步還原問題的場景。至於到微秒,在多執行緒程式下,如果程序停止響應,可以從日誌時間看是否死鎖。

一般格式:

[2017-01-09 12:16:30.541]

2.打log位置的檔名和**行數。這個不用說,用於定位問題根源。其實最重要是防止扯皮。因為程式設計師大多喜歡copy-paste,如果你不加檔名和行數,某程式設計師copy了你的**,修改了點,出錯了,到時候把你拉下水。

一般格式:

[2017-01-09 12:16:30.541][network.c:541]

3. 有程序id。有些log機制在程序重啟時,不會重新生成乙個日誌檔案,而是直接在同乙個日誌檔案後面新增日誌。或者,有時候同一程式的多個程序同時執行,可能也會寫入到同乙個日誌檔案。

一般格式:

[2017-01-09 12:16:30.541][network.c:541][pid=15529]

4.有執行緒id。在多執行緒程式,如果不加執行緒id,很難追溯程式的行為

一般格式:

[2017-01-09 12:16:30.541][network.c:541][pid=15529][thread=0x12345]

5.有日誌的級別。日誌是反映問題的,有不同緊急程式的問題,自然有不同的日誌級別。一般採用error,warning,info,debug。定義不同級別,也可以方便在日誌查詢問題**。

一般格式:

[2017-01-09 12:16:30.541][network.c:541][pid=15529][thread=0x12345][error]

打log的場景:

1. 申請記憶體時,失敗的話,要把申請大小列印出來。以前我申請記憶體失敗也是簡單地列印:

[2017-01-09 12:16:30.541][network.c:541][pid=15529][thread=0x12345][error]failed to allocate memory

後來在重構時遇到乙個問題:程序跑的時間一久,大概一天多,別的程式向它發訊息都會收到失敗響應,在日誌裡就是一大堆記憶體失敗的訊息"failed to allocate memory"。用"free"命令來看,物理記憶體還有好幾g空閒,而用「top」命令來看,該程序也只是佔700m記憶體。當時我就懷疑是不是記憶體碎片導致。於是我把申請記憶體的大小也列印出來,就收到一堆這樣的

[2017-01-09 12:16:30.541][network.c:541][pid=15529][thread=0x12345][error]failed to allocate memory of size 65536

[2017-01-09 12:16:30.588][network.c:541][pid=15529][thread=0x12345][error]failed to allocate memory of size 1048576

當時就看那些**引用的資料結構,最小也有64k,大的16m都有,基本乙個結構包括很多個大陣列。當時就把那些陣列全改為指標,再進一步申請,**繁瑣了,但這種問題再也不會出現。再看bug系統,原來這個問題存在很多,在其它程式也存在,當時都找不到根因,只是用過一段時間重啟程序來解決

2. 函式引數非空判斷時,要列印日誌。原因不說,看對比:

之前

if ( ( pinfo == null ) || ( phandler == null ) ) 

之後

if ( ( pinfo == null ) || ( phandler == null ) ) 

3. 載入和解除安裝模組,無論是正常還是異常情況都要列印。畢竟這些操作大多都是一次性操作。對效能影響不大。

[2017-01-09 12:16:30.588][modules.c:54][pid=15529][thread=0x12345][error]failed to load module libftp.so, error=module already loaded

4. 操作檔案目錄時,失敗要把檔名和錯誤碼列印出來。如

[2017-01-09 12:16:30.588][config.c:120][pid=15529][thread=0x12345][error]failed to open file conf/ftp.xml, errno=(13:permission denied)

假設這個錯誤導致程序初始化失敗,且環境在客戶那邊,維護人員就可以確認並自己解決這個問題。

5. 操作socket時,把ip,埠號或路徑名(unix socket )和錯誤碼列印出來。如

[2017-01-09 12:16:30.588][network.c:541][pid=15529][thread=0x12345][error]failed to connect to host (10.17.128.10:9981), errno=(111:connection refused)

6. 運算元據庫時,把相應操作的ip,埠,庫,使用者名稱,sql語句和錯誤列印出來。如

[2017-01-09 12:16:30.588][dbmgr.c:781][pid=15529][thread=0x12345][error]user tiger failed to operate in host (10.17.128.10:3365) with db test, sql="select * from users", error="no table users exists"

在客戶環境下,維護人員可以通過命令列來驗證這些問題,來確定問題。可能有人會考慮安全性,畢竟在日誌中把ip,埠,庫,使用者名稱都暴露出來了,這樣好像不妥。但如果是從事過通訊行業的網上問題維護,就知道,可維護性比這種細節的安全性還要重要。

7. 建立新程序時,需要把程式名,引數和錯誤碼列印出來。如

[2017-01-09 12:16:30.588][process.c:154][pid=15529][thread=0x12345][error]failed to execute program "iptables -l", errno=(2:no such file or directory)

往往在客戶環境,由於運維人員水平參差不齊,可能誤操作或漏操作,導致檔案缺失或許可權出錯,這種錯誤在公司的模擬環境根本不會出現。如果日誌夠詳細,能夠減少很多任務作量。

8. 解析檔案時,需要把檔名,字段,行號列印出來。如

[2017-01-09 12:16:30.588][config.c:120][pid=15529][thread=0x12345][error]failed to parse file conf/ftp.xml, line:20, tag is not closed

結語:上面的原則,基本是每一條是血的教訓。以前在h時見得太多因為日誌不全導致的麻煩,前方的客戶經理不斷向客戶懇求寬限時間,維護人員不斷地在客戶環境找出蛛絲馬跡,後方領導也不斷地調配資源來跟蹤問題,後方測試人員不斷地測試,嘗試問題復現,後方開發人員就不斷地看**。在z也見過因為日誌不全,導致被客戶罰錢次數過多,整個產品都虧損了。像@帝都鐵匠 說的「感覺學會log,程式就算入門了」。

關於log4j的一些使用心得

做實驗時需要將程式產生的異常記錄到日誌中,因此用到了log4j,log4j是第三方的庫,用之前需要匯入到專案中,匯入之後,最關鍵的步驟是寫配置檔案 log4j.properties,下面針對我在實驗中遇到的問題來簡單關於寫配置檔案的一些事情。如果乙個專案很大,我們可能需要將日誌寫到不同的檔案中去,這...

IOCP的一些心得

iocp的工作執行緒的個數一般設定為processors 2 2,這是綜合考慮了工作執行緒可能是等待 掛起 正在執行的狀態。如果你測試出更好的結果,以你的為標準。iocp的工作執行緒由系統排程和優化,不要去干預執行緒的排程,除非你自信能超越系統的排程。在遇到奇怪的問題時,可以嘗試減少iocp工作執行...

Qt 的一些心得

一.背景刷成黑色,前景色設為白色。方法一 paltette方式,經測試,該方法不會影響到其他控制項,推薦使用 qpalette bgpal palette bgpal.setcolor qpalette background,qcolor 0,0 0,255 qpalette background,...