go-grpc + context 请求打通

req + req_id -> http-server -> grpc-client -> grpc-server

客户端/web生成req_id, 在通参中传递到http-server, 加入到request.context上.

return func(w http.ResponseWriter, r *http.Request) {
    reqID := r.URL.Query().Get("request_id")
    if reqID == "" {
        reqID = UUID()
    }
    r = r.WithContext(context.WithValue(r.Context(), "req_id", reqID))
    ...
}

grpc-client调用时, 通过metadata将req_id传递到grpc-server上.

func WithOutgoingReqID(ctx context.Context) context.Context {
	rawid := ctx.Value(constant.ReqIDKey)
	if rawid != nil {
		if reqid, ok := rawid.(string); ok {
			return metadata.AppendToOutgoingContext(ctx, constant.ReqIDKey, reqid)
		}
	}
	reqid := program.StrUUID()
	return metadata.AppendToOutgoingContext(ctx, constant.ReqIDKey, reqid)
}

call(ctx context.Context) {
    ctx = WithOutgoingReqID(ctx)
}

grpc-server是handle函数的ctx参数中,提取req-id,以及客户端地址.

func GetReqInfo(ctx context.Context) (reqid string, ip string) {
	rreqid := ctx.Value(constant.ReqIDKey)
	if s, ok := rreqid.(string); ok {
		reqid = s
	}
	p, ok := peer.FromContext(ctx)
	if ok {
		ip = p.Addr.String()
	}
	return
}