Skip to content

Commit 21dc93c

Browse files
authored
feat: add log-dir flag to vscodessh for debuggability (#10514)
1 parent 08844d0 commit 21dc93c

File tree

2 files changed

+33
-12
lines changed

2 files changed

+33
-12
lines changed

cli/vscodessh.go

+23-5
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ func (r *RootCmd) vscodeSSH() *clibase.Cmd {
3434
var (
3535
sessionTokenFile string
3636
urlFile string
37+
logDir string
3738
networkInfoDir string
3839
networkInfoInterval time.Duration
3940
)
@@ -129,13 +130,25 @@ func (r *RootCmd) vscodeSSH() *clibase.Cmd {
129130
}
130131
}
131132

133+
// The VS Code extension obtains the PID of the SSH process to
134+
// read files to display logs and network info.
135+
//
136+
// We get the parent PID because it's assumed `ssh` is calling this
137+
// command via the ProxyCommand SSH option.
138+
pid := os.Getppid()
139+
132140
var logger slog.Logger
133-
if r.verbose {
134-
logger = slog.Make(sloghuman.Sink(inv.Stdout)).Leveled(slog.LevelDebug)
141+
if logDir != "" {
142+
logFilePath := filepath.Join(logDir, fmt.Sprintf("%d.log", pid))
143+
logFile, err := fs.OpenFile(logFilePath, os.O_CREATE|os.O_WRONLY, 0o600)
144+
if err != nil {
145+
return xerrors.Errorf("open log file %q: %w", logFilePath, err)
146+
}
147+
defer logFile.Close()
148+
logger = slog.Make(sloghuman.Sink(logFile)).Leveled(slog.LevelDebug)
135149
}
136-
137150
if r.disableDirect {
138-
_, _ = fmt.Fprintln(inv.Stderr, "Direct connections disabled.")
151+
logger.Info(ctx, "direct connections disabled")
139152
}
140153
agentConn, err := client.DialWorkspaceAgent(ctx, agent.ID, &codersdk.DialWorkspaceAgentOptions{
141154
Logger: logger,
@@ -166,7 +179,7 @@ func (r *RootCmd) vscodeSSH() *clibase.Cmd {
166179
//
167180
// We get the parent PID because it's assumed `ssh` is calling this
168181
// command via the ProxyCommand SSH option.
169-
networkInfoFilePath := filepath.Join(networkInfoDir, fmt.Sprintf("%d.json", os.Getppid()))
182+
networkInfoFilePath := filepath.Join(networkInfoDir, fmt.Sprintf("%d.json", pid))
170183

171184
statsErrChan := make(chan error, 1)
172185
cb := func(start, end time.Time, virtual, _ map[netlogtype.Connection]netlogtype.Counts) {
@@ -213,6 +226,11 @@ func (r *RootCmd) vscodeSSH() *clibase.Cmd {
213226
Description: "Specifies a directory to write network information periodically.",
214227
Value: clibase.StringOf(&networkInfoDir),
215228
},
229+
{
230+
Flag: "log-dir",
231+
Description: "Specifies a directory to write logs to.",
232+
Value: clibase.StringOf(&logDir),
233+
},
216234
{
217235
Flag: "session-token-file",
218236
Description: "Specifies a file that contains a session token.",

cli/vscodessh_test.go

+10-7
Original file line numberDiff line numberDiff line change
@@ -43,20 +43,23 @@ func TestVSCodeSSH(t *testing.T) {
4343
"--url-file", "/url",
4444
"--session-token-file", "/token",
4545
"--network-info-dir", "/net",
46+
"--log-dir", "/log",
4647
"--network-info-interval", "25ms",
4748
fmt.Sprintf("coder-vscode--%s--%s", user.Username, workspace.Name),
4849
)
4950
ptytest.New(t).Attach(inv)
5051

5152
waiter := clitest.StartWithWaiter(t, inv.WithContext(ctx))
5253

53-
assert.Eventually(t, func() bool {
54-
entries, err := afero.ReadDir(fs, "/net")
55-
if err != nil {
56-
return false
57-
}
58-
return len(entries) > 0
59-
}, testutil.WaitLong, testutil.IntervalFast)
54+
for _, dir := range []string{"/net", "/log"} {
55+
assert.Eventually(t, func() bool {
56+
entries, err := afero.ReadDir(fs, dir)
57+
if err != nil {
58+
return false
59+
}
60+
return len(entries) > 0
61+
}, testutil.WaitLong, testutil.IntervalFast)
62+
}
6063
waiter.Cancel()
6164

6265
if err := waiter.Wait(); err != nil {

0 commit comments

Comments
 (0)