目前,幾乎全部的軟件系統都具有日誌功能,經過日誌咱們能夠在軟件運行異常時定位軟件遇到的問題,還原應用程序異常時的運行狀態。git
雖然系統上線前通過了嚴格的測試工做,可是生產環境業務的複雜性、不可預測性使得軟件工程師沒法確保系統上線後不會發生故障。爲了可以在系統發生異常時對系統故障進行分析與定位,引入日誌系統成爲全部軟件系統研發的必然選擇。github
在上篇文章《go-kit微服務-HTTP REST》中實現了算術運算的HTTP服務,這篇文章將基於Gokit中間件機制爲其增長日誌記錄功能。bash
本質上講,go-kit中間件採用了裝飾者模式,傳入Endpoint對象,封裝部分業務邏輯,而後返回Endpoint對象。微信
打開service.go
文件,加入以下代碼:微服務
// ServiceMiddleware define service middleware
type ServiceMiddleware func(Service) Service
複製代碼
新建文件loggings.go
,新建類型loggingMiddleware
,該類型中嵌入了Service
,還包含一個logger
屬性,代碼以下所示:post
// loggingMiddleware Make a new type
// that contains Service interface and logger instance
type loggingMiddleware struct {
Service
logger log.Logger
}
複製代碼
下來建立一個方法LoggingMiddleware
把日誌記錄對象嵌入中間件。該方法接受日誌對象,返回ServiceMiddleware
,而ServiceMiddleware
能夠傳入Service
對象,這樣就能夠對Service
增長一層裝飾。代碼以下:測試
// LoggingMiddleware make logging middleware
func LoggingMiddleware(logger log.Logger) ServiceMiddleware {
return func(next Service) Service {
return loggingMiddleware{next, logger}
}
}
複製代碼
接下來就可讓新的類型loggingMiddleware
實現Service
的接口方法了。實現方法時能夠在其中使用日誌對象記錄調用方法、調用時間、傳入參數、輸出結果、調用耗時等信息。下面以Add
方法爲例進行實現,其餘方法與之相似:ui
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
的包裝,代碼以下所示(帶有註釋的一行即爲新增代碼):spa
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請求接口進行測試,便可看到輸出的日誌信息:3d
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獲取。
本文首發於本人微信公衆號【兮一昂吧】,歡迎掃碼關注!