Skip to content

Commit a8d0ddc

Browse files
committed
Some refactoring wrt logging and debugging
- clangd launcher has been moved into main module, removing an unneded indirection. - streams management functions now resides in their own module. - file logging has been downgraded from an object to a function
1 parent 3ec5d2a commit a8d0ddc

File tree

5 files changed

+123
-188
lines changed

5 files changed

+123
-188
lines changed

Diff for: handler/handler.go

+7-29
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ import (
66
"encoding/json"
77
"fmt"
88
"io"
9-
"io/ioutil"
109
"log"
1110
"os"
1211
"regexp"
@@ -33,19 +32,19 @@ func Setup(cliPath string, _enableLogging bool, _asyncProcessing bool) {
3332
type CLangdStarter func() (stdin io.WriteCloser, stdout io.ReadCloser, stderr io.ReadCloser)
3433

3534
// NewInoHandler creates and configures an InoHandler.
36-
func NewInoHandler(stdin io.ReadCloser, stdout io.WriteCloser, logStreams *StreamLogger, startClangd CLangdStarter, board Board) *InoHandler {
35+
func NewInoHandler(stdio io.ReadWriteCloser, clangdStdio io.ReadWriteCloser, board Board) *InoHandler {
3736
handler := &InoHandler{
38-
clangdProc: ClangdProc{
39-
Start: startClangd,
40-
Logs: logStreams,
41-
},
4237
data: make(map[lsp.DocumentURI]*FileData),
4338
config: BoardConfig{
4439
SelectedBoard: board,
4540
},
4641
}
47-
handler.startClangd()
48-
stdStream := jsonrpc2.NewBufferedStream(logStreams.AttachStdInOut(stdin, stdout), jsonrpc2.VSCodeObjectCodec{})
42+
43+
clangdStream := jsonrpc2.NewBufferedStream(clangdStdio, jsonrpc2.VSCodeObjectCodec{})
44+
clangdHandler := jsonrpc2.AsyncHandler(jsonrpc2.HandlerWithError(handler.FromClangd))
45+
handler.ClangdConn = jsonrpc2.NewConn(context.Background(), clangdStream, clangdHandler)
46+
47+
stdStream := jsonrpc2.NewBufferedStream(stdio, jsonrpc2.VSCodeObjectCodec{})
4948
var stdHandler jsonrpc2.Handler = jsonrpc2.HandlerWithError(handler.FromStdio)
5049
if asyncProcessing {
5150
stdHandler = AsyncHandler{
@@ -64,18 +63,11 @@ func NewInoHandler(stdin io.ReadCloser, stdout io.WriteCloser, logStreams *Strea
6463
type InoHandler struct {
6564
StdioConn *jsonrpc2.Conn
6665
ClangdConn *jsonrpc2.Conn
67-
clangdProc ClangdProc
6866
data map[lsp.DocumentURI]*FileData
6967
config BoardConfig
7068
synchronizer Synchronizer
7169
}
7270

73-
// ClangdProc contains the process input / output streams for clangd.
74-
type ClangdProc struct {
75-
Start func() (io.WriteCloser, io.ReadCloser, io.ReadCloser)
76-
Logs *StreamLogger
77-
}
78-
7971
// FileData gathers information on a .ino source file.
8072
type FileData struct {
8173
sourceText string
@@ -86,20 +78,6 @@ type FileData struct {
8678
version int
8779
}
8880

89-
// StartClangd starts the clangd process and connects its input / output streams.
90-
func (handler *InoHandler) startClangd() {
91-
clangdWrite, clangdRead, clangdErr := handler.clangdProc.Start()
92-
if enableLogging {
93-
go io.Copy(handler.clangdProc.Logs.ClangdErr, clangdErr)
94-
} else {
95-
go io.Copy(ioutil.Discard, clangdErr)
96-
}
97-
srw := handler.clangdProc.Logs.AttachClangdInOut(clangdRead, clangdWrite)
98-
clangdStream := jsonrpc2.NewBufferedStream(srw, jsonrpc2.VSCodeObjectCodec{})
99-
clangdHandler := jsonrpc2.AsyncHandler(jsonrpc2.HandlerWithError(handler.FromClangd))
100-
handler.ClangdConn = jsonrpc2.NewConn(context.Background(), clangdStream, clangdHandler)
101-
}
102-
10381
// StopClangd closes the connection to the clangd process.
10482
func (handler *InoHandler) StopClangd() {
10583
handler.ClangdConn.Close()

Diff for: handler/streamlog.go

-147
This file was deleted.

Diff for: main.go

+38-12
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,10 @@ import (
77
"log"
88
"os"
99
"os/exec"
10+
"path/filepath"
1011

1112
"github.com/bcmi-labs/arduino-language-server/handler"
13+
"github.com/bcmi-labs/arduino-language-server/streams"
1214
)
1315

1416
var clangdPath string
@@ -29,29 +31,53 @@ func main() {
2931
flag.StringVar(&loggingBasePath, "logpath", ".", "Location where to write logging files to when logging is enabled")
3032
flag.Parse()
3133

32-
// var stdinLog, stdoutLog, clangdinLog, clangdoutLog, clangderrLog io.Writer
33-
var logStreams *handler.StreamLogger
3434
if enableLogging {
35-
var err error
36-
logStreams, err = handler.NewStreamLogger(loggingBasePath)
37-
if err != nil {
38-
log.Fatal(err)
39-
}
40-
defer logStreams.Close()
41-
42-
log.SetOutput(logStreams.Default)
35+
logfile := openLogFile("inols-err.log")
36+
defer logfile.Close()
37+
log.SetOutput(logfile)
4338
} else {
44-
logStreams = handler.NewNoopLogger()
4539
log.SetOutput(os.Stderr)
4640
}
4741

4842
handler.Setup(cliPath, enableLogging, true)
4943
initialBoard := handler.Board{Fqbn: initialFqbn, Name: initialBoardName}
50-
inoHandler := handler.NewInoHandler(os.Stdin, os.Stdout, logStreams, startClangd, initialBoard)
44+
45+
clangdStdout, clangdStdin, clangdStderr := startClangd()
46+
clangdStdio := streams.NewReadWriteCloser(clangdStdin, clangdStdout)
47+
if enableLogging {
48+
logfile := openLogFile("inols-clangd.log")
49+
defer logfile.Close()
50+
clangdStdio = streams.LogReadWriteCloserToFile(clangdStdio, logfile)
51+
52+
errLogfile := openLogFile("inols-clangd-err.log")
53+
defer errLogfile.Close()
54+
go io.Copy(errLogfile, clangdStderr)
55+
}
56+
57+
stdio := streams.NewReadWriteCloser(os.Stdin, os.Stdout)
58+
if enableLogging {
59+
logfile := openLogFile("inols.log")
60+
defer logfile.Close()
61+
stdio = streams.LogReadWriteCloserToFile(stdio, logfile)
62+
}
63+
64+
inoHandler := handler.NewInoHandler(stdio, clangdStdio, initialBoard)
5165
defer inoHandler.StopClangd()
5266
<-inoHandler.StdioConn.DisconnectNotify()
5367
}
5468

69+
func openLogFile(name string) *os.File {
70+
path := filepath.Join(loggingBasePath, name)
71+
logfile, err := os.Create(path)
72+
if err != nil {
73+
log.Fatalf("Error opening log file: %s", err)
74+
} else {
75+
abs, _ := filepath.Abs(path)
76+
log.Println("logging to " + abs)
77+
}
78+
return logfile
79+
}
80+
5581
func startClangd() (clangdIn io.WriteCloser, clangdOut io.ReadCloser, clangdErr io.ReadCloser) {
5682
if enableLogging {
5783
log.Println("Starting clangd process:", clangdPath)

Diff for: streams/dumper.go

+45
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
package streams
2+
3+
import (
4+
"fmt"
5+
"io"
6+
"os"
7+
)
8+
9+
// LogReadWriteCloserToFile return a proxy for the given upstream io.ReadWriteCloser
10+
// that forward and logs all read/write/close operations on the given file.
11+
func LogReadWriteCloserToFile(upstream io.ReadWriteCloser, file *os.File) io.ReadWriteCloser {
12+
return &dumper{upstream, file}
13+
}
14+
15+
type dumper struct {
16+
upstream io.ReadWriteCloser
17+
logfile *os.File
18+
}
19+
20+
func (d *dumper) Read(buff []byte) (int, error) {
21+
n, err := d.upstream.Read(buff)
22+
if err != nil {
23+
d.logfile.Write([]byte(fmt.Sprintf("<<< Read Error: %s\n", err)))
24+
} else {
25+
d.logfile.Write([]byte(fmt.Sprintf("<<< Read %d bytes:\n%s\n", n, buff[:n])))
26+
}
27+
return n, err
28+
}
29+
30+
func (d *dumper) Write(buff []byte) (int, error) {
31+
n, err := d.upstream.Write(buff)
32+
if err != nil {
33+
_, _ = d.logfile.Write([]byte(fmt.Sprintf(">>> Write Error: %s\n", err)))
34+
} else {
35+
_, _ = d.logfile.Write([]byte(fmt.Sprintf(">>> Wrote %d bytes:\n%s\n", n, buff[:n])))
36+
}
37+
return n, err
38+
}
39+
40+
func (d *dumper) Close() error {
41+
err := d.upstream.Close()
42+
_, _ = d.logfile.Write([]byte(fmt.Sprintf("--- Stream closed, err=%s\n", err)))
43+
_ = d.logfile.Close()
44+
return err
45+
}

Diff for: streams/streams.go

+33
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
package streams
2+
3+
import "io"
4+
5+
// NewReadWriteCloser create an io.ReadWriteCloser from given io.ReadCloser and io.WriteCloser.
6+
func NewReadWriteCloser(in io.ReadCloser, out io.WriteCloser) io.ReadWriteCloser {
7+
return &combinedReadWriteCloser{in, out}
8+
}
9+
10+
type combinedReadWriteCloser struct {
11+
reader io.ReadCloser
12+
writer io.WriteCloser
13+
}
14+
15+
func (sd *combinedReadWriteCloser) Read(p []byte) (int, error) {
16+
return sd.reader.Read(p)
17+
}
18+
19+
func (sd *combinedReadWriteCloser) Write(p []byte) (int, error) {
20+
return sd.writer.Write(p)
21+
}
22+
23+
func (sd *combinedReadWriteCloser) Close() error {
24+
ierr := sd.reader.Close()
25+
oerr := sd.writer.Close()
26+
if ierr != nil {
27+
return ierr
28+
}
29+
if oerr != nil {
30+
return oerr
31+
}
32+
return nil
33+
}

0 commit comments

Comments
 (0)