Skip to content

Commit

Permalink
Add workaround for jsonrpc2 message logging issue
Browse files Browse the repository at this point in the history
  • Loading branch information
fhs committed Jun 19, 2023
1 parent 447231c commit 4288b27
Show file tree
Hide file tree
Showing 4 changed files with 84 additions and 3 deletions.
2 changes: 1 addition & 1 deletion cmd/L/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ func run(cfg *config.Config, args []string) error {
stream := jsonrpc2.NewBufferedStream(conn, jsonrpc2.VSCodeObjectCodec{})
var opts []jsonrpc2.ConnOpt
if cfg.Verbose {
opts = append(opts, jsonrpc2.LogMessages(log.Default()))
opts = append(opts, lsp.LogMessages(log.Default()))
}
rpc := jsonrpc2.NewConn(ctx, stream, nil, opts...)
defer rpc.Close()
Expand Down
3 changes: 2 additions & 1 deletion internal/lsp/acmelsp/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
"github.com/fhs/go-lsp-internal/lsp/protocol"
"github.com/sourcegraph/jsonrpc2"

"github.com/fhs/acme-lsp/internal/lsp"
"github.com/fhs/acme-lsp/internal/lsp/acmelsp/config"
"github.com/fhs/acme-lsp/internal/lsp/proxy"
"github.com/fhs/acme-lsp/internal/lsp/text"
Expand Down Expand Up @@ -132,7 +133,7 @@ func (c *Client) init(conn net.Conn, cfg *ClientConfig) error {
})
var opts []jsonrpc2.ConnOpt
if cfg.RPCTrace {
opts = append(opts, jsonrpc2.LogMessages(log.Default()))
opts = append(opts, lsp.LogMessages(log.Default()))
}
if c.rpc != nil {
c.rpc.Close()
Expand Down
3 changes: 2 additions & 1 deletion internal/lsp/acmelsp/proxy.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"fmt"
"log"

"github.com/fhs/acme-lsp/internal/lsp"
"github.com/fhs/acme-lsp/internal/lsp/acmelsp/config"
"github.com/fhs/acme-lsp/internal/lsp/proxy"
"github.com/fhs/acme-lsp/internal/lsp/text"
Expand Down Expand Up @@ -179,7 +180,7 @@ func ListenAndServeProxy(ctx context.Context, cfg *config.Config, ss *ServerSet,
})
var opts []jsonrpc2.ConnOpt
if cfg.RPCTrace {
opts = append(opts, jsonrpc2.LogMessages(log.Default()))
opts = append(opts, lsp.LogMessages(log.Default()))

}
rpc := jsonrpc2.NewConn(ctx, stream, handler, opts...)
Expand Down
79 changes: 79 additions & 0 deletions internal/lsp/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,15 @@ package lsp

import (
"context"
"encoding/json"
"fmt"
"log"
"path/filepath"
"sync"

"github.com/fhs/acme-lsp/internal/lsp/text"
"github.com/fhs/go-lsp-internal/lsp/protocol"
"github.com/sourcegraph/jsonrpc2"
)

func ServerProvidesCodeAction(cap *protocol.ServerCapabilities, kind protocol.CodeActionKind) bool {
Expand Down Expand Up @@ -139,3 +142,79 @@ func DirsToWorkspaceFolders(dirs []string) ([]protocol.WorkspaceFolder, error) {
}
return workspaces, nil
}

// LogMessages causes all messages sent and received on conn to be
// logged using the provided logger.
//
// This works around a bug in jsonrpc2.
// Upstream PR: https://github.com/sourcegraph/jsonrpc2/pull/71
func LogMessages(logger jsonrpc2.Logger) jsonrpc2.ConnOpt {
return func(c *jsonrpc2.Conn) {
// Remember reqs we have received so we can helpfully show the
// request method in OnSend for responses.
var (
mu sync.Mutex
reqMethods = map[jsonrpc2.ID]string{}
)

jsonrpc2.OnRecv(func(req *jsonrpc2.Request, resp *jsonrpc2.Response) {
switch {
case resp != nil:
var method string
if req != nil {
method = req.Method
} else {
method = "(no matching request)"
}
switch {
case resp.Result != nil:
result, _ := json.Marshal(resp.Result)
logger.Printf("jsonrpc2: --> result #%s: %s: %s\n", resp.ID, method, result)
case resp.Error != nil:
err, _ := json.Marshal(resp.Error)
logger.Printf("jsonrpc2: --> error #%s: %s: %s\n", resp.ID, method, err)
}

case req != nil:
mu.Lock()
reqMethods[req.ID] = req.Method
mu.Unlock()

params, _ := json.Marshal(req.Params)
if req.Notif {
logger.Printf("jsonrpc2: --> notif: %s: %s\n", req.Method, params)
} else {
logger.Printf("jsonrpc2: --> request #%s: %s: %s\n", req.ID, req.Method, params)
}
}
})(c)
jsonrpc2.OnSend(func(req *jsonrpc2.Request, resp *jsonrpc2.Response) {
switch {
case resp != nil:
mu.Lock()
method := reqMethods[resp.ID]
delete(reqMethods, resp.ID)
mu.Unlock()
if method == "" {
method = "(no previous request)"
}

if resp.Result != nil {
result, _ := json.Marshal(resp.Result)
logger.Printf("jsonrpc2: <-- result #%s: %s: %s\n", resp.ID, method, result)
} else {
err, _ := json.Marshal(resp.Error)
logger.Printf("jsonrpc2: <-- error #%s: %s: %s\n", resp.ID, method, err)
}

case req != nil:
params, _ := json.Marshal(req.Params)
if req.Notif {
logger.Printf("jsonrpc2: <-- notif: %s: %s\n", req.Method, params)
} else {
logger.Printf("jsonrpc2: <-- request #%s: %s: %s\n", req.ID, req.Method, params)
}
}
})(c)
}
}

0 comments on commit 4288b27

Please sign in to comment.