.gitignore added
[dotfiles/.git] / .config / coc / extensions / coc-go-data / tools / pkg / mod / golang.org / x / tools@v0.1.1-0.20210319172145-bda8f5cee399 / internal / lsp / protocol / log.go
1 // Copyright 2019 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
4
5 package protocol
6
7 import (
8         "context"
9         "fmt"
10         "io"
11         "strings"
12         "sync"
13         "time"
14
15         "golang.org/x/tools/internal/jsonrpc2"
16 )
17
18 type loggingStream struct {
19         stream jsonrpc2.Stream
20         logMu  sync.Mutex
21         log    io.Writer
22 }
23
24 // LoggingStream returns a stream that does LSP protocol logging too
25 func LoggingStream(str jsonrpc2.Stream, w io.Writer) jsonrpc2.Stream {
26         return &loggingStream{stream: str, log: w}
27 }
28
29 func (s *loggingStream) Read(ctx context.Context) (jsonrpc2.Message, int64, error) {
30         msg, count, err := s.stream.Read(ctx)
31         if err == nil {
32                 s.logCommon(msg, true)
33         }
34         return msg, count, err
35 }
36
37 func (s *loggingStream) Write(ctx context.Context, msg jsonrpc2.Message) (int64, error) {
38         s.logCommon(msg, false)
39         count, err := s.stream.Write(ctx, msg)
40         return count, err
41 }
42
43 func (s *loggingStream) Close() error {
44         return s.stream.Close()
45 }
46
47 type req struct {
48         method string
49         start  time.Time
50 }
51
52 type mapped struct {
53         mu          sync.Mutex
54         clientCalls map[string]req
55         serverCalls map[string]req
56 }
57
58 var maps = &mapped{
59         sync.Mutex{},
60         make(map[string]req),
61         make(map[string]req),
62 }
63
64 // these 4 methods are each used exactly once, but it seemed
65 // better to have the encapsulation rather than ad hoc mutex
66 // code in 4 places
67 func (m *mapped) client(id string) req {
68         m.mu.Lock()
69         defer m.mu.Unlock()
70         v := m.clientCalls[id]
71         delete(m.clientCalls, id)
72         return v
73 }
74
75 func (m *mapped) server(id string) req {
76         m.mu.Lock()
77         defer m.mu.Unlock()
78         v := m.serverCalls[id]
79         delete(m.serverCalls, id)
80         return v
81 }
82
83 func (m *mapped) setClient(id string, r req) {
84         m.mu.Lock()
85         defer m.mu.Unlock()
86         m.clientCalls[id] = r
87 }
88
89 func (m *mapped) setServer(id string, r req) {
90         m.mu.Lock()
91         defer m.mu.Unlock()
92         m.serverCalls[id] = r
93 }
94
95 const eor = "\r\n\r\n\r\n"
96
97 func (s *loggingStream) logCommon(msg jsonrpc2.Message, isRead bool) {
98         s.logMu.Lock()
99         defer s.logMu.Unlock()
100         direction, pastTense := "Received", "Received"
101         get, set := maps.client, maps.setServer
102         if isRead {
103                 direction, pastTense = "Sending", "Sent"
104                 get, set = maps.server, maps.setClient
105         }
106         if msg == nil || s.log == nil {
107                 return
108         }
109         tm := time.Now()
110         tmfmt := tm.Format("15:04:05.000 PM")
111
112         buf := strings.Builder{}
113         fmt.Fprintf(&buf, "[Trace - %s] ", tmfmt) // common beginning
114         switch msg := msg.(type) {
115         case *jsonrpc2.Call:
116                 id := fmt.Sprint(msg.ID())
117                 fmt.Fprintf(&buf, "%s request '%s - (%s)'.\n", direction, msg.Method(), id)
118                 fmt.Fprintf(&buf, "Params: %s%s", msg.Params(), eor)
119                 set(id, req{method: msg.Method(), start: tm})
120         case *jsonrpc2.Notification:
121                 fmt.Fprintf(&buf, "%s notification '%s'.\n", direction, msg.Method())
122                 fmt.Fprintf(&buf, "Params: %s%s", msg.Params(), eor)
123         case *jsonrpc2.Response:
124                 id := fmt.Sprint(msg.ID())
125                 if err := msg.Err(); err != nil {
126                         fmt.Fprintf(s.log, "[Error - %s] %s #%s %s%s", pastTense, tmfmt, id, err, eor)
127                         return
128                 }
129                 cc := get(id)
130                 elapsed := tm.Sub(cc.start)
131                 fmt.Fprintf(&buf, "%s response '%s - (%s)' in %dms.\n",
132                         direction, cc.method, id, elapsed/time.Millisecond)
133                 fmt.Fprintf(&buf, "Result: %s%s", msg.Result(), eor)
134         }
135         s.log.Write([]byte(buf.String()))
136 }