# 12.1 應用日志
我們期望開發的Web應用程序能夠把整個程序運行過程中出現的各種事件一一記錄下來,Go語言中提供了一個簡易的log包,我們使用該包可以方便的實現日志記錄的功能,這些日志都是基于fmt包的打印再結合panic之類的函數來進行一般的打印、拋出錯誤處理。Go目前標準包只是包含了簡單的功能,如果我們想把我們的應用日志保存到文件,然后又能夠結合日志實現很多復雜的功能(編寫過Java或者C++的讀者應該都使用過log4j和log4cpp之類的日志工具),可以使用第三方開發的一個日志系統,`https://github.com/cihub/seelog`,它實現了很強大的日志功能。接下來我們介紹如何通過該日志系統來實現我們應用的日志功能。
## seelog介紹
seelog是用Go語言實現的一個日志系統,它提供了一些簡單的函數來實現復雜的日志分配、過濾和格式化。主要有如下特性:
- XML的動態配置,可以不用重新編譯程序而動態的加載配置信息
- 支持熱更新,能夠動態改變配置而不需要重啟應用
- 支持多輸出流,能夠同時把日志輸出到多種流中、例如文件流、網絡流等
- 支持不同的日志輸出
- 命令行輸出
- 文件輸出
- 緩存輸出
- 支持log rotate
- SMTP郵件
上面只列舉了部分特性,seelog是一個特別強大的日志處理系統,詳細的內容請參看官方wiki。接下來我將簡要介紹一下如何在項目中使用它:
首先安裝seelog
go get -u github.com/cihub/seelog
然后我們來看一個簡單的例子:
package main
import log "github.com/cihub/seelog"
func main() {
defer log.Flush()
log.Info("Hello from Seelog!")
}
編譯后運行如果出現了`Hello from seelog`,說明seelog日志系統已經成功安裝并且可以正常運行了。
## 基于seelog的自定義日志處理
seelog支持自定義日志處理,下面是我基于它自定義的日志處理包的部分內容:
package logs
import (
"errors"
"fmt"
seelog "github.com/cihub/seelog"
"io"
)
var Logger seelog.LoggerInterface
func loadAppConfig() {
appConfig := `
<seelog minlevel="warn">
<outputs formatid="common">
<rollingfile type="size" filename="/data/logs/roll.log" maxsize="100000" maxrolls="5"/>
<filter levels="critical">
<file path="/data/logs/critical.log" formatid="critical"/>
<smtp formatid="criticalemail" senderaddress="astaxie@gmail.com" sendername="ShortUrl API" hostname="smtp.gmail.com" hostport="587" username="mailusername" password="mailpassword">
<recipient address="xiemengjun@gmail.com"/>
</smtp>
</filter>
</outputs>
<formats>
<format id="common" format="%Date/%Time [%LEV] %Msg%n" />
<format id="critical" format="%File %FullPath %Func %Msg%n" />
<format id="criticalemail" format="Critical error on our server!\n %Time %Date %RelFile %Func %Msg \nSent by Seelog"/>
</formats>
</seelog>
`
logger, err := seelog.LoggerFromConfigAsBytes([]byte(appConfig))
if err != nil {
fmt.Println(err)
return
}
UseLogger(logger)
}
func init() {
DisableLog()
loadAppConfig()
}
// DisableLog disables all library log output
func DisableLog() {
Logger = seelog.Disabled
}
// UseLogger uses a specified seelog.LoggerInterface to output library log.
// Use this func if you are using Seelog logging system in your app.
func UseLogger(newLogger seelog.LoggerInterface) {
Logger = newLogger
}
上面主要實現了三個函數,
- `DisableLog`
初始化全局變量Logger為seelog的禁用狀態,主要為了防止Logger被多次初始化
- `loadAppConfig`
根據配置文件初始化seelog的配置信息,這里我們把配置文件通過字符串讀取設置好了,當然也可以通過讀取XML文件。里面的配置說明如下:
- seelog
minlevel參數可選,如果被配置,高于或等于此級別的日志會被記錄,同理maxlevel。
- outputs
輸出信息的目的地,這里分成了兩份數據,一份記錄到log rotate文件里面。另一份設置了filter,如果這個錯誤級別是critical,那么將發送報警郵件。
- formats
定義了各種日志的格式
- `UseLogger`
設置當前的日志器為相應的日志處理
上面我們定義了一個自定義的日志處理包,下面就是使用示例:
package main
import (
"net/http"
"project/logs"
"project/configs"
"project/routes"
)
func main() {
addr, _ := configs.MainConfig.String("server", "addr")
logs.Logger.Info("Start server at:%v", addr)
err := http.ListenAndServe(addr, routes.NewMux())
logs.Logger.Critical("Server err:%v", err)
}
## 發生錯誤發送郵件
上面的例子解釋了如何設置發送郵件,我們通過如下的smtp配置用來發送郵件:
<smtp formatid="criticalemail" senderaddress="astaxie@gmail.com" sendername="ShortUrl API" hostname="smtp.gmail.com" hostport="587" username="mailusername" password="mailpassword">
<recipient address="xiemengjun@gmail.com"/>
</smtp>
郵件的格式通過criticalemail配置,然后通過其他的配置發送郵件服務器的配置,通過recipient配置接收郵件的用戶,如果有多個用戶可以再添加一行。
要測試這個代碼是否正常工作,可以在代碼中增加類似下面的一個假消息。不過記住過后要把它刪除,否則上線之后就會收到很多垃圾郵件。
logs.Logger.Critical("test Critical message")
現在,只要我們的應用在線上記錄一個Critical的信息,你的郵箱就會收到一個Email,這樣一旦線上的系統出現問題,你就能立馬通過郵件獲知,就能及時的進行處理。
## 使用應用日志
對于應用日志,每個人的應用場景可能會各不相同,有些人利用應用日志來做數據分析,有些人利用應用日志來做性能分析,有些人來做用戶行為分析,還有些就是純粹的記錄,以方便應用出現問題的時候輔助查找問題。
舉一個例子,我們需要跟蹤用戶嘗試登陸系統的操作。這里會把成功與不成功的嘗試都記錄下來。記錄成功的使用"Info"日志級別,而不成功的使用"warn"級別。如果想查找所有不成功的登陸,我們可以利用linux的grep之類的命令工具,如下:
# cat /data/logs/roll.log | grep "failed login"
2012-12-11 11:12:00 WARN : failed login attempt from 11.22.33.44 username password
通過這種方式我們就可以很方便的查找相應的信息,這樣有利于我們針對應用日志做一些統計和分析。另外我們還需要考慮日志的大小,對于一個高流量的Web應用來說,日志的增長是相當可怕的,所以我們在seelog的配置文件里面設置了logrotate,這樣就能保證日志文件不會因為不斷變大而導致我們的磁盤空間不夠引起問題。
## 小結
通過上面對seelog系統及如何基于它進行自定義日志系統的學習,現在我們可以很輕松的隨需構建一個合適的功能強大的日志處理系統了。日志處理系統為數據分析提供了可靠的數據源,比如通過對日志的分析,我們可以進一步優化系統,或者應用出現問題時方便查找定位問題,另外seelog也提供了日志分級功能,通過對minlevel的配置,我們可以很方便的設置測試或發布版本的輸出消息級別。
## links
* [目錄](<preface.md>)
* 上一章: [部署與維護](<12.0.md>)
* 下一節: [網站錯誤處理](<12.2.md>)
- 目錄
- Go環境配置
- Go安裝
- GOPATH 與工作空間
- Go 命令
- Go開發工具
- 小結
- Go語言基礎
- 你好,Go
- Go基礎
- 流程和函數
- struct
- 面向對象
- interface
- 并發
- 小結
- Web基礎
- web工作方式
- Go搭建一個簡單的web服務
- Go如何使得web工作
- Go的http包詳解
- 小結
- 表單
- 處理表單的輸入
- 驗證表單的輸入
- 預防跨站腳本
- 防止多次遞交表單
- 處理文件上傳
- 小結
- 訪問數據庫
- database/sql接口
- 使用MySQL數據庫
- 使用SQLite數據庫
- 使用PostgreSQL數據庫
- 使用beedb庫進行ORM開發
- NOSQL數據庫操作
- 小結
- session和數據存儲
- session和cookie
- Go如何使用session
- session存儲
- 預防session劫持
- 小結
- 文本文件處理
- XML處理
- JSON處理
- 正則處理
- 模板處理
- 文件操作
- 字符串處理
- 小結
- Web服務
- Socket編程
- WebSocket
- REST
- RPC
- 小結
- 安全與加密
- 預防CSRF攻擊
- 確保輸入過濾
- 避免XSS攻擊
- 避免SQL注入
- 存儲密碼
- 加密和解密數據
- 小結
- 國際化和本地化
- 設置默認地區
- 本地化資源
- 國際化站點
- 小結
- 錯誤處理,調試和測試
- 錯誤處理
- 使用GDB調試
- Go怎么寫測試用例
- 小結
- 部署與維護
- 應用日志
- 網站錯誤處理
- 應用部署
- 備份和恢復
- 小結
- 如何設計一個Web框架
- 項目規劃
- 自定義路由器設計
- controller設計
- 日志和配置設計
- 實現博客的增刪改
- 小結
- 擴展Web框架
- 靜態文件支持
- Session支持
- 表單支持
- 用戶認證
- 多語言支持
- pprof支持
- 小結
- 參考資料