mirror of
https://github.com/golang/go
synced 2024-11-18 21:24:44 -07:00
206ec5b82a
Change-Id: Idc662385ed08bd62593ccd1d54afd3fa8c1a7d29 Reviewed-on: https://go-review.googlesource.com/c/tools/+/222558 Run-TryBot: Ian Cottrell <iancottrell@google.com> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Robert Findley <rfindley@google.com>
116 lines
2.9 KiB
Go
116 lines
2.9 KiB
Go
// Copyright 2020 The Go Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style
|
|
// license that can be found in the LICENSE file.
|
|
|
|
package lsprpc
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"time"
|
|
|
|
"golang.org/x/tools/internal/jsonrpc2"
|
|
"golang.org/x/tools/internal/lsp/telemetry"
|
|
"golang.org/x/tools/internal/telemetry/event"
|
|
)
|
|
|
|
type telemetryHandler struct{}
|
|
|
|
func (h telemetryHandler) Deliver(ctx context.Context, r *jsonrpc2.Request, delivered bool) bool {
|
|
stats := h.getStats(ctx)
|
|
if stats != nil {
|
|
stats.delivering()
|
|
}
|
|
return false
|
|
}
|
|
|
|
func (h telemetryHandler) Cancel(ctx context.Context, conn *jsonrpc2.Conn, id jsonrpc2.ID, cancelled bool) bool {
|
|
return false
|
|
}
|
|
|
|
func (h telemetryHandler) Request(ctx context.Context, conn *jsonrpc2.Conn, direction jsonrpc2.Direction, r *jsonrpc2.WireRequest) context.Context {
|
|
if r.Method == "" {
|
|
panic("no method in rpc stats")
|
|
}
|
|
stats := &rpcStats{
|
|
method: r.Method,
|
|
start: time.Now(),
|
|
direction: direction,
|
|
payload: r.Params,
|
|
}
|
|
ctx = context.WithValue(ctx, statsKey, stats)
|
|
mode := telemetry.Outbound
|
|
if direction == jsonrpc2.Receive {
|
|
mode = telemetry.Inbound
|
|
}
|
|
ctx, stats.close = event.StartSpan(ctx, r.Method,
|
|
telemetry.Method.Of(r.Method),
|
|
telemetry.RPCDirection.Of(mode),
|
|
telemetry.RPCID.Of(r.ID),
|
|
)
|
|
telemetry.Started.Record(ctx, 1)
|
|
_, stats.delivering = event.StartSpan(ctx, "queued")
|
|
return ctx
|
|
}
|
|
|
|
func (h telemetryHandler) Response(ctx context.Context, conn *jsonrpc2.Conn, direction jsonrpc2.Direction, r *jsonrpc2.WireResponse) context.Context {
|
|
return ctx
|
|
}
|
|
|
|
func (h telemetryHandler) Done(ctx context.Context, err error) {
|
|
stats := h.getStats(ctx)
|
|
if err != nil {
|
|
ctx = event.Label(ctx, telemetry.StatusCode.Of("ERROR"))
|
|
} else {
|
|
ctx = event.Label(ctx, telemetry.StatusCode.Of("OK"))
|
|
}
|
|
elapsedTime := time.Since(stats.start)
|
|
latencyMillis := float64(elapsedTime) / float64(time.Millisecond)
|
|
telemetry.Latency.Record(ctx, latencyMillis)
|
|
stats.close()
|
|
}
|
|
|
|
func (h telemetryHandler) Read(ctx context.Context, bytes int64) context.Context {
|
|
telemetry.SentBytes.Record(ctx, bytes)
|
|
return ctx
|
|
}
|
|
|
|
func (h telemetryHandler) Wrote(ctx context.Context, bytes int64) context.Context {
|
|
telemetry.ReceivedBytes.Record(ctx, bytes)
|
|
return ctx
|
|
}
|
|
|
|
const eol = "\r\n\r\n\r\n"
|
|
|
|
func (h telemetryHandler) Error(ctx context.Context, err error) {
|
|
}
|
|
|
|
func (h telemetryHandler) getStats(ctx context.Context) *rpcStats {
|
|
stats, ok := ctx.Value(statsKey).(*rpcStats)
|
|
if !ok || stats == nil {
|
|
method, ok := ctx.Value(telemetry.Method).(string)
|
|
if !ok {
|
|
method = "???"
|
|
}
|
|
stats = &rpcStats{
|
|
method: method,
|
|
close: func() {},
|
|
}
|
|
}
|
|
return stats
|
|
}
|
|
|
|
type rpcStats struct {
|
|
method string
|
|
direction jsonrpc2.Direction
|
|
id *jsonrpc2.ID
|
|
payload *json.RawMessage
|
|
start time.Time
|
|
delivering func()
|
|
close func()
|
|
}
|
|
|
|
type statsKeyType int
|
|
|
|
const statsKey = statsKeyType(0)
|