Как объединить результаты разных событий в golang для func HandleRPC из пакета «google.golang.org/grpc/stats»

// 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. Может кто-нибудь, пожалуйста, помогите мне с этим, Спасибо!

Интересный. До вашего вопроса я был незнаком с stats. Я подозреваю, что возникает неявный вопрос: как связать данные о разрозненных событиях внутри каждого RPC? Вы можете обновить контекст в своих методах TagConn и TagRPC, указав уникальный идентификатор, чтобы связать их. Если вы хотите сохранить эти данные после срока жизни каждого Handler, вам нужно передать свой механизм сохранения в обработчик при его создании.

DazWilkin 13.04.2024 20:39

@DazWilkin Но я не получаю событие *stats.InHeader, с помощью которого я могу получить доступ к метаданным ответа внутри методов TagConn или TagRPC

LST 14.04.2024 11:17

Как показывает ваш код (!?), вы получаете заголовки запросов в своем методе HandleRPC, когда получаете тип *stats.InHeader. Заголовки ответов (если таковые имеются) будут доступны, когда вы получите тип *stats.OutHeader (для которого у вас нет ветки switch). Обработчик (все его методы) содержат context.Context, и вы можете добавить к нему пары ключ:значение, чтобы представить обработчик. состояние его соединений и RPC каждого соединения.

DazWilkin 14.04.2024 16:54

@DazWilkin, как сказано в вашем первом комментарии и после ссылки на эту ссылку grpc/grpc-go/issues/5823#issuecomment-1349707446 Мне удалось это решить

LST 17.04.2024 23:59
Создание API ввода вопросов на разных языках программирования (Python, PHP, Go и Node.js)
Создание API ввода вопросов на разных языках программирования (Python, PHP, Go и Node.js)
API ввода вопросов - это полезный инструмент для интеграции моделей машинного обучения, таких как ChatGPT, в приложения, требующие обработки...
1
4
80
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий
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)
            }
        }
    }

}
  1. Добавьте изменяемый объект в контекст в TagRPC
  2. Измените изменяемый объект в событии *stats.InHeader.
  3. Наконец получите доступ к объекту на *stats.End

Другие вопросы по теме