目前,幾乎全部的軟件系統都具有日誌功能,經過日誌咱們能夠在軟件運行異常時定位軟件遇到的問題,還原應用程序異常時的運行狀態。git
雖然系統上線前通過了嚴格的測試工做,可是生產環境業務的複雜性、不可預測性使得軟件工程師沒法確保系統上線後不會發生故障。爲了可以在系統發生異常時對系統故障進行分析與定位,引入日誌系統成爲全部軟件系統研發的必然選擇。github
在上篇文章《go-kit微服務-HTTP REST》中實現了算術運算的HTTP服務,這篇文章將基於Gokit中間件機制爲其增長日誌記錄功能。bash
本質上講,go-kit中間件採用了裝飾者模式,傳入Endpoint對象,封裝部分業務邏輯,而後返回Endpoint對象。微信
打開service.go
文件,加入以下代碼:markdown
// ServiceMiddleware define service middleware type ServiceMiddleware func(Service) Service 複製代碼
新建文件loggings.go
,新建類型loggingMiddleware
,該類型中嵌入了Service
,還包含一個logger
屬性,代碼以下所示:微服務
// loggingMiddleware Make a new type // that contains Service interface and logger instance type loggingMiddleware struct { Service logger log.Logger } 複製代碼
下來建立一個方法LoggingMiddleware
把日誌記錄對象嵌入中間件。該方法接受日誌對象,返回ServiceMiddleware
,而ServiceMiddleware
能夠傳入Service
對象,這樣就能夠對Service
增長一層裝飾。代碼以下:oop
// LoggingMiddleware make logging middleware func LoggingMiddleware(logger log.Logger) ServiceMiddleware { return func(next Service) Service { return loggingMiddleware{next, logger} } } 複製代碼
接下來就可讓新的類型loggingMiddleware
實現Service
的接口方法了。實現方法時能夠在其中使用日誌對象記錄調用方法、調用時間、傳入參數、輸出結果、調用耗時等信息。下面以Add
方法爲例進行實現,其餘方法與之相似:post
func (mw loggingMiddleware) Add(a, b int) (ret int) { defer func(beign time.Time) { mw.logger.Log( "function", "Add", "a", a, "b", b, "result", ret, "took", time.Since(beign), ) }(time.Now()) ret = mw.Service.Add(a, b) return ret } 複製代碼
打開main.go
,調用LoggingMiddleware
建立日誌中間件實現對svc
的包裝,代碼以下所示(帶有註釋的一行即爲新增代碼):測試
func main() { ctx := context.Background() errChan := make(chan error) var logger log.Logger { logger = log.NewLogfmtLogger(os.Stderr) logger = log.With(logger, "ts", log.DefaultTimestampUTC) logger = log.With(logger, "caller", log.DefaultCaller) } var svc Service svc = ArithmeticService{} // add logging middleware svc = LoggingMiddleware(logger)(svc) endpoint := MakeArithmeticEndpoint(svc) r := MakeHttpHandler(ctx, endpoint, logger) go func() { fmt.Println("Http Server start at port:9000") handler := r errChan <- http.ListenAndServe(":9000", handler) }() go func() { c := make(chan os.Signal, 1) signal.Notify(c, syscall.SIGINT, syscall.SIGTERM) errChan <- fmt.Errorf("%s", <-c) }() fmt.Println(<-errChan) } 複製代碼
在控制檯編譯並運行應用程序,而後經過Postman請求接口進行測試,便可看到輸出的日誌信息:spa
ts=2019-02-18T05:43:57.902971Z caller=logging.go:25 function=Add a=10 b=1 result=11 took=0s ts=2019-02-18T05:44:10.116234Z caller=logging.go:25 function=Add a=10 b=1 result=11 took=0s ts=2019-02-18T05:44:11.2682718Z caller=logging.go:25 function=Add a=10 b=1 result=11 took=0s 複製代碼
本文藉助go-kit的中間件機制爲微服務增長了日誌功能。因爲Gokit中間件採用裝飾者模式,新增的日誌功能對Endpoint、Service、Transport三個層次均無代碼入侵,實現即插即用的效果,這一機制在開發中將很是有利於團隊之間的配合。固然,本文采用的日誌記錄僅僅是經過控制檯輸出,還沒法真正應用於生產環境,從此有時間繼續研究其餘方式。
本文代碼可經過github獲取。
本文首發於本人微信公衆號【兮一昂吧】,歡迎掃碼關注!