diff --git a/internal/jsonrpc2/jsonrpc2_test.go b/internal/jsonrpc2/jsonrpc2_test.go index 53afface..89252fd1 100644 --- a/internal/jsonrpc2/jsonrpc2_test.go +++ b/internal/jsonrpc2/jsonrpc2_test.go @@ -167,9 +167,9 @@ func (h *handle) Cancel(ctx context.Context, conn *jsonrpc2.Conn, id jsonrpc2.ID func (h *handle) Request(ctx context.Context, direction jsonrpc2.Direction, r *jsonrpc2.WireRequest) context.Context { if h.log { if r.ID != nil { - log.Printf("%v call [%v] %s %s", direction, r.ID, r.Method, r.Params) + log.Printf("%v call [%v] %s %v", direction, r.ID, r.Method, r.Params) } else { - log.Printf("%v notification %s %s", direction, r.Method, r.Params) + log.Printf("%v notification %s %v", direction, r.Method, r.Params) } ctx = context.WithValue(ctx, "method", r.Method) ctx = context.WithValue(ctx, "start", time.Now()) @@ -181,7 +181,7 @@ func (h *handle) Response(ctx context.Context, direction jsonrpc2.Direction, r * if h.log { method := ctx.Value("method") elapsed := time.Since(ctx.Value("start").(time.Time)) - log.Printf("%v response in %v [%v] %s %s", direction, elapsed, r.ID, method, r.Result) + log.Printf("%v response in %v [%v] %s %v", direction, elapsed, r.ID, method, r.Result) } return ctx } diff --git a/internal/lsp/cache/cache.go b/internal/lsp/cache/cache.go index 713e5e75..ed2468fa 100644 --- a/internal/lsp/cache/cache.go +++ b/internal/lsp/cache/cache.go @@ -72,12 +72,12 @@ func (c *cache) GetFile(uri span.URI) source.FileHandle { } } -func (c *cache) NewSession(log xlog.Logger) source.Session { +func (c *cache) NewSession(ctx context.Context) source.Session { index := atomic.AddInt64(&sessionIndex, 1) s := &session{ cache: c, id: strconv.FormatInt(index, 10), - log: log, + log: xlog.From(ctx), overlays: make(map[span.URI]*overlay), filesWatchMap: NewWatchMap(), } diff --git a/internal/lsp/cmd/cmd.go b/internal/lsp/cmd/cmd.go index 03aa3d2d..c4590379 100644 --- a/internal/lsp/cmd/cmd.go +++ b/internal/lsp/cmd/cmd.go @@ -140,7 +140,7 @@ func (app *Application) connect(ctx context.Context) (*connection, error) { switch app.Remote { case "": connection := newConnection(app) - connection.Server = lsp.NewClientServer(app.cache, connection.Client) + ctx, connection.Server = lsp.NewClientServer(ctx, app.cache, connection.Client) return connection, connection.initialize(ctx) case "internal": internalMu.Lock() @@ -153,9 +153,12 @@ func (app *Application) connect(ctx context.Context) (*connection, error) { cr, sw, _ := os.Pipe() sr, cw, _ := os.Pipe() var jc *jsonrpc2.Conn - jc, connection.Server, _ = protocol.NewClient(jsonrpc2.NewHeaderStream(cr, cw), connection.Client) + ctx, jc, connection.Server = protocol.NewClient(ctx, jsonrpc2.NewHeaderStream(cr, cw), connection.Client) go jc.Run(ctx) - go lsp.NewServer(app.cache, jsonrpc2.NewHeaderStream(sr, sw)).Run(ctx) + go func() { + ctx, srv := lsp.NewServer(ctx, app.cache, jsonrpc2.NewHeaderStream(sr, sw)) + srv.Run(ctx) + }() if err := connection.initialize(ctx); err != nil { return nil, err } @@ -169,7 +172,7 @@ func (app *Application) connect(ctx context.Context) (*connection, error) { } stream := jsonrpc2.NewHeaderStream(conn, conn) var jc *jsonrpc2.Conn - jc, connection.Server, _ = protocol.NewClient(stream, connection.Client) + ctx, jc, connection.Server = protocol.NewClient(ctx, stream, connection.Client) go jc.Run(ctx) return connection, connection.initialize(ctx) } diff --git a/internal/lsp/cmd/serve.go b/internal/lsp/cmd/serve.go index ac023128..9b45f9f3 100644 --- a/internal/lsp/cmd/serve.go +++ b/internal/lsp/cmd/serve.go @@ -79,7 +79,7 @@ func (s *Serve) Run(ctx context.Context, args ...string) error { } // For debugging purposes only. - run := func(srv *lsp.Server) { + run := func(ctx context.Context, srv *lsp.Server) { srv.Conn.AddHandler(&handler{trace: s.Trace, out: out}) go srv.Run(ctx) } @@ -90,7 +90,7 @@ func (s *Serve) Run(ctx context.Context, args ...string) error { return lsp.RunServerOnPort(ctx, s.app.cache, s.Port, run) } stream := jsonrpc2.NewHeaderStream(os.Stdin, os.Stdout) - srv := lsp.NewServer(s.app.cache, stream) + ctx, srv := lsp.NewServer(ctx, s.app.cache, stream) srv.Conn.AddHandler(&handler{trace: s.Trace, out: out}) return srv.Run(ctx) } diff --git a/internal/lsp/lsp_test.go b/internal/lsp/lsp_test.go index f4480592..7c8fdf84 100644 --- a/internal/lsp/lsp_test.go +++ b/internal/lsp/lsp_test.go @@ -42,9 +42,9 @@ func testLSP(t *testing.T, exporter packagestest.Exporter) { data := tests.Load(t, exporter, "testdata") defer data.Exported.Cleanup() - log := xlog.New(xlog.StdSink{}) + ctx = xlog.With(ctx, xlog.StdSink{}) cache := cache.New() - session := cache.NewSession(log) + session := cache.NewSession(ctx) view := session.NewView(ctx, viewName, span.FileURI(data.Config.Dir)) view.SetEnv(data.Config.Env) for filename, content := range data.Config.Overlay { diff --git a/internal/lsp/protocol/protocol.go b/internal/lsp/protocol/protocol.go index c1bbb767..254b2f9f 100644 --- a/internal/lsp/protocol/protocol.go +++ b/internal/lsp/protocol/protocol.go @@ -40,19 +40,19 @@ func (canceller) Cancel(ctx context.Context, conn *jsonrpc2.Conn, id jsonrpc2.ID return true } -func NewClient(stream jsonrpc2.Stream, client Client) (*jsonrpc2.Conn, Server, xlog.Logger) { - log := xlog.New(NewLogger(client)) +func NewClient(ctx context.Context, stream jsonrpc2.Stream, client Client) (context.Context, *jsonrpc2.Conn, Server) { + ctx = xlog.With(ctx, NewLogger(client)) conn := jsonrpc2.NewConn(stream) - conn.AddHandler(&clientHandler{log: log, client: client}) - return conn, &serverDispatcher{Conn: conn}, log + conn.AddHandler(&clientHandler{log: xlog.From(ctx), client: client}) + return ctx, conn, &serverDispatcher{Conn: conn} } -func NewServer(stream jsonrpc2.Stream, server Server) (*jsonrpc2.Conn, Client, xlog.Logger) { +func NewServer(ctx context.Context, stream jsonrpc2.Stream, server Server) (context.Context, *jsonrpc2.Conn, Client) { conn := jsonrpc2.NewConn(stream) client := &clientDispatcher{Conn: conn} - log := xlog.New(NewLogger(client)) - conn.AddHandler(&serverHandler{log: log, server: server}) - return conn, client, log + ctx = xlog.With(ctx, NewLogger(client)) + conn.AddHandler(&serverHandler{log: xlog.From(ctx), server: server}) + return ctx, conn, client } func sendParseError(ctx context.Context, log xlog.Logger, req *jsonrpc2.Request, err error) { diff --git a/internal/lsp/server.go b/internal/lsp/server.go index a75821e4..8d384235 100644 --- a/internal/lsp/server.go +++ b/internal/lsp/server.go @@ -18,32 +18,32 @@ import ( ) // NewClientServer -func NewClientServer(cache source.Cache, client protocol.Client) *Server { - return &Server{ +func NewClientServer(ctx context.Context, cache source.Cache, client protocol.Client) (context.Context, *Server) { + ctx = xlog.With(ctx, protocol.NewLogger(client)) + return ctx, &Server{ client: client, - session: cache.NewSession(xlog.New(protocol.NewLogger(client))), + session: cache.NewSession(ctx), } } // NewServer starts an LSP server on the supplied stream, and waits until the // stream is closed. -func NewServer(cache source.Cache, stream jsonrpc2.Stream) *Server { +func NewServer(ctx context.Context, cache source.Cache, stream jsonrpc2.Stream) (context.Context, *Server) { s := &Server{} - var log xlog.Logger - s.Conn, s.client, log = protocol.NewServer(stream, s) - s.session = cache.NewSession(log) - return s + ctx, s.Conn, s.client = protocol.NewServer(ctx, stream, s) + s.session = cache.NewSession(ctx) + return ctx, s } // RunServerOnPort starts an LSP server on the given port and does not exit. // This function exists for debugging purposes. -func RunServerOnPort(ctx context.Context, cache source.Cache, port int, h func(s *Server)) error { +func RunServerOnPort(ctx context.Context, cache source.Cache, port int, h func(ctx context.Context, s *Server)) error { return RunServerOnAddress(ctx, cache, fmt.Sprintf(":%v", port), h) } // RunServerOnPort starts an LSP server on the given port and does not exit. // This function exists for debugging purposes. -func RunServerOnAddress(ctx context.Context, cache source.Cache, addr string, h func(s *Server)) error { +func RunServerOnAddress(ctx context.Context, cache source.Cache, addr string, h func(ctx context.Context, s *Server)) error { ln, err := net.Listen("tcp", addr) if err != nil { return err @@ -53,7 +53,7 @@ func RunServerOnAddress(ctx context.Context, cache source.Cache, addr string, h if err != nil { return err } - h(NewServer(cache, jsonrpc2.NewHeaderStream(conn, conn))) + h(NewServer(ctx, cache, jsonrpc2.NewHeaderStream(conn, conn))) } } diff --git a/internal/lsp/source/source_test.go b/internal/lsp/source/source_test.go index c38e38cc..7bd469e7 100644 --- a/internal/lsp/source/source_test.go +++ b/internal/lsp/source/source_test.go @@ -38,9 +38,9 @@ func testSource(t *testing.T, exporter packagestest.Exporter) { data := tests.Load(t, exporter, "../testdata") defer data.Exported.Cleanup() - log := xlog.New(xlog.StdSink{}) + ctx = xlog.With(ctx, xlog.StdSink{}) cache := cache.New() - session := cache.NewSession(log) + session := cache.NewSession(ctx) r := &runner{ view: session.NewView(ctx, "source_test", span.FileURI(data.Config.Dir)), data: data, diff --git a/internal/lsp/source/view.go b/internal/lsp/source/view.go index 996d659a..f40553d6 100644 --- a/internal/lsp/source/view.go +++ b/internal/lsp/source/view.go @@ -111,7 +111,7 @@ type Cache interface { FileSystem // NewSession creates a new Session manager and returns it. - NewSession(log xlog.Logger) Session + NewSession(ctx context.Context) Session // FileSet returns the shared fileset used by all files in the system. FileSet() *token.FileSet diff --git a/internal/lsp/xlog/xlog.go b/internal/lsp/xlog/xlog.go index a8d5bdad..6d9fc36c 100644 --- a/internal/lsp/xlog/xlog.go +++ b/internal/lsp/xlog/xlog.go @@ -35,11 +35,6 @@ type Sink interface { // StdSink is a Sink that writes to the standard log package. type StdSink struct{} -// New returns a logger for the provided sink. -func New(sink Sink) Logger { - return Logger{sink: sink} -} - // Errorf is intended for the logging of errors that we could not easily return // to the client but that caused problems internally. func (l Logger) Errorf(ctx context.Context, format string, args ...interface{}) { @@ -69,3 +64,27 @@ func (StdSink) Log(ctx context.Context, level Level, message string) { log.Print("Debug: ", message) } } + +type contextKeyType int + +const contextKey = contextKeyType(0) + +func With(ctx context.Context, sink Sink) context.Context { + return context.WithValue(ctx, contextKey, sink) +} + +func From(ctx context.Context) Logger { + return Logger{sink: ctx.Value(contextKey).(Sink)} +} + +func Errorf(ctx context.Context, format string, args ...interface{}) { + From(ctx).Errorf(ctx, format, args...) +} + +func Infof(ctx context.Context, format string, args ...interface{}) { + From(ctx).Infof(ctx, format, args...) +} + +func Debugf(ctx context.Context, format string, args ...interface{}) { + From(ctx).Debugf(ctx, format, args...) +}