Go - 實現專案內鏈路追蹤(二)

新亮筆記發表於2021-02-10

上篇文章 Go - 實現專案內鏈路追蹤 分享了,通過 鏈路 ID 可以將 請求資訊響應資訊呼叫第三方介面的資訊除錯資訊執行的 SQL 資訊執行的 Redis 資訊 串起來,記錄的具體引數在檔案中都有介紹。

這篇文章在上面的基礎上,新增 2 個功能點:

  1. 新增將 呼叫 gRPC 介面資訊 記錄到 Trace 中;
  2. 新增對記錄的敏感資訊進行脫敏處理;

呼叫 gRPC 介面資訊

記錄引數

Object,結構如下:

type Grpc struct {
	Timestamp   string                 `json:"timestamp"`             // 時間,格式:2006-01-02 15:04:05
	Addr        string                 `json:"addr"`                  // 地址
	Method      string                 `json:"method"`                // 操作方法
	Meta        metadata.MD            `json:"meta"`                  // Mate 資訊
	Request     map[string]interface{} `json:"request"`               // 請求資訊
	Response    map[string]interface{} `json:"response"`              // 返回資訊
	CostSeconds float64                `json:"cost_seconds"`          // 執行時間(單位秒)
	Code        string                 `json:"err_code,omitempty"`    // 錯誤碼
	Message     string                 `json:"err_message,omitempty"` // 錯誤資訊
}

如何收集引數

封裝了一個 grpclient 包:

  • 支援設定 DialTimeout
  • 支援設定 UnaryInterceptor
  • 支援設定 KeepaliveParams
  • 支援設定 TransportCredentials

主要是在攔截器 Interceptor 中進行收集。

示例程式碼

例項化 gRPC client

// TODO 需從配置檔案中獲取
target := "127.0.0.1:9988"
secret := "abcdef"

clientInterceptor := NewClientInterceptor(func(message []byte) (authorization string, err error) {
	return GenerateSign(secret, message)
})

conn, err := grpclient.New(target,
	grpclient.WithKeepAlive(keepAlive),
	grpclient.WithDialTimeout(time.Second*5),
	grpclient.WithUnaryInterceptor(clientInterceptor.UnaryInterceptor),
)

return &clientConn{
	conn: conn,
}, err

呼叫具體方法

// 核心:傳遞 core.Context 給 Interceptor 使用
client := hello.NewHelloClient(d.grpconn.Conn())
client.SayHello(grpc.ContextWithValueAndTimeout(c, time.Second*3), &hello.HelloRequest{Name: "Hello World"})

敏感資訊脫敏

敏感資訊脫敏又稱為動態資料掩碼(Dynamic Data Masking,簡稱為DDM)能夠防止把敏感資料暴露給未經授權的使用者。

根據專案要求可以約定一些規範,例如:

型別 要求 示例 說明
手機號 前 3 後 4 132****7986 定長 11 位數字
郵箱地址 前 1 後 1 l**w@gmail.com 僅對 @ 之前的郵箱名稱進行掩碼
姓名 隱姓 *鴻章 將姓氏隱藏
密碼 不輸出 ******
銀行卡卡號 前 6 後 4 622888******5676 銀行卡卡號最多 19 位數字
身份證號 前 1 後 1 1******7 定長 18 位

如何實現

我現在的實現方案是:自定義 MarshalJSON(),歡迎大佬們提出更好的方案。

示例程式碼

// 定義 Mobile 型別
type Mobile string

// 自定義 MarshalJSON()
func (m Mobile) MarshalJSON() ([]byte, error) {
	if len(m) != 11 {
		return []byte(`"` + m + `"`), nil
	}

	v := fmt.Sprintf("%s****%s", m[:3], m[len(m)-4:])
	return []byte(`"` + v + `"`), nil
}

測試

type message struct {
	Mobile    ddm.Mobile   `json:"mobile"`
}

msg := new(message)
msg.Mobile = ddm.Mobile("13288889999")

marshal, _ := json.Marshal(msg)
fmt.Println(string(marshal))

// 輸出:{"mobile":"132****9999"}

小結

本篇文章新增了 2 個實用的功能點,大家趕緊使用起來吧。關於 敏感資訊脫敏 期待各位大佬不吝賜教,提出更好的解決方案,謝謝!

以上程式碼都在 go-gin-api 專案中,地址:https://github.com/xinliangnote/go-gin-api

相關文章