// HandleRPC implements per-RPC tracing and stats instrumentation.
func (c *statsHandler) HandleRPC(ctx context.Context, rs stats.RPCStats) {
switch rs := rs.(type) {
case *stats.InHeader:
if rs.Client {
fmt.Printf(rs.Header)
}
case *stats.End:
ign := false
c.lock.RLock()
ign = c.ignore
c.lock.RUnlock()
if !ign {
duration := rs.EndTime.Sub(rs.BeginTime)
var st string
s, ok := status.FromError(rs.Error)
if ok {
st = s.Code().String()
}
c.results <- &callResult{rs.Error, st, duration, rs.EndTime}
if c.hasLog {
c.log.Debugw("Received RPC Stats",
"statsID", c.id, "code", st, "error", rs.Error,
"duration", duration, "stats", rs)
}
}
}
}
У меня есть response metadata событие *stats.InHeader и остальная часть grpc stats события *stats.End, я хочу объединить metadata и grpc stats в один объект структуры callResult в конце вызова grpc. Я совершенно не уверен, как это реализовать, я действительно новичок в grpc. Может кто-нибудь, пожалуйста, помогите мне с этим, Спасибо!
@DazWilkin Но я не получаю событие *stats.InHeader, с помощью которого я могу получить доступ к метаданным ответа внутри методов TagConn или TagRPC
Как показывает ваш код (!?), вы получаете заголовки запросов в своем методе HandleRPC, когда получаете тип *stats.InHeader. Заголовки ответов (если таковые имеются) будут доступны, когда вы получите тип *stats.OutHeader (для которого у вас нет ветки switch). Обработчик (все его методы) содержат context.Context, и вы можете добавить к нему пары ключ:значение, чтобы представить обработчик. состояние его соединений и RPC каждого соединения.
@DazWilkin, как сказано в вашем первом комментарии и после ссылки на эту ссылку grpc/grpc-go/issues/5823#issuecomment-1349707446 Мне удалось это решить

type MutableObject struct {
InMetadata metadata.MD // Example mutable field
}
// TagRPC implements per-RPC context management.
func (c *statsHandler) TagRPC(ctx context.Context, info *stats.RPCTagInfo) context.Context {
ctx = context.WithValue(ctx, "InHeader", &MutableObject{})
return ctx
}
// HandleRPC implements per-RPC tracing and stats instrumentation.
func (c *statsHandler) HandleRPC(ctx context.Context, rs stats.RPCStats) {
switch rs := rs.(type) {
case *stats.InHeader:
var headerValue metadata.MD
if rs.Client {
ign := false
c.lock.RLock()
ign = c.ignore
c.lock.RUnlock()
if !ign {
headerValue = rs.Header
if header, ok := ctx.Value("InHeader").(*MutableObject); ok {
header.InMetadata = headerValue
}
}
}
case *stats.End:
ign := false
c.lock.RLock()
ign = c.ignore
c.lock.RUnlock()
if !ign {
duration := rs.EndTime.Sub(rs.BeginTime)
var st string
s, ok := status.FromError(rs.Error)
if ok {
st = s.Code().String()
}
// Retrieve the header value from the context
var ts time.Time
if header, ok := ctx.Value("InHeader").(*MutableObject); ok {
databroker_timestamp, err := strconv.ParseInt(header.InMetadata["ts"][0], 10, 64)
if err == nil {
ts = time.Unix(int64(math.Abs(float64(databroker_timestamp)/1000000000)), databroker_timestamp%1000000000)
}
}
c.results <- &callResult{rs.Error, st, duration, rs.EndTime, ts, 10, 10}
if c.hasLog {
c.log.Debugw("Received RPC Stats",
"statsID", c.id, "code", st, "error", rs.Error,
"duration", duration, "stats", rs)
}
}
}
}
TagRPC*stats.InHeader.*stats.End
Интересный. До вашего вопроса я был незнаком с
stats. Я подозреваю, что возникает неявный вопрос: как связать данные о разрозненных событиях внутри каждого RPC? Вы можете обновить контекст в своих методахTagConnиTagRPC, указав уникальный идентификатор, чтобы связать их. Если вы хотите сохранить эти данные после срока жизни каждогоHandler, вам нужно передать свой механизм сохранения в обработчик при его создании.