Skip to content

Commit 2fee55b

Browse files
authored
[vscode-extension] Logging events in logfile (#1745)
## Summary Added capability to log sequence of events and potential errors in "Re-open in devbox shell environment" functionality of the extension. This involved adding a log file in `.devbox/extension.log` file which both the vscode extension process and devbox binary will output their logs into. The reason to add this capability is "Re-open in devbox shell" functionality relies on multiple sub-processes running a sequence of events correctly. So if one breaks along the way, often times, the error message for it will be lost. This PR makes sure that in such cases, the user has a way of capturing the error messages that may have been lost. ## How was it tested? 1. in devbox, run: `devbox run build` this creates a binary in `dist/devbox` copy the absolute path to that binary 2. in an editor, edit the file `/usr/local/bin/devbox` in line 414 to be similar to below: ```bash #local -r bin="${INSTALL_DIR}/${version}_${platform}/${TOOL_NAME}" # absolute path to devbox binary in dist/ local -r bin="/Users/mohsenansari/code/jetpack/go.jetpack.io/devbox/dist/devbox" ``` 3. Back in devbox repo in Terminal `cd vscode-extension` then run `vsce package` (if you don't have vsce install do it via `npm i -g vsce` 4. Open vscode and uninstall the already installed devbox extension. Then reload vscode. 5. In Terminal, run `code --install-extension devbox-0.1.3.vsix` 6. In VSCode go to settings(UI) and search for devbox. Enable debug mode by ticking its checkbox. 7. cmd + shift + p and search for "Devbox: Re-open in Devbox shell environment" 8. Confirm an `extension.log` file is created in `.devbox/` directory and contains the logs for reopen in devbox feature.
1 parent 1732602 commit 2fee55b

File tree

3 files changed

+78
-9
lines changed

3 files changed

+78
-9
lines changed

internal/boxcli/integrate.go

Lines changed: 46 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,19 +6,23 @@ package boxcli
66
import (
77
"bytes"
88
"encoding/json"
9+
"fmt"
10+
"log"
11+
"os"
912
"os/exec"
1013
"slices"
1114
"strings"
15+
"time"
1216

1317
"github.com/spf13/cobra"
1418
"github.com/zealic/go2node"
15-
"go.jetpack.io/devbox/internal/debug"
1619
"go.jetpack.io/devbox/internal/devbox"
1720
"go.jetpack.io/devbox/internal/devbox/devopt"
1821
)
1922

2023
type integrateCmdFlags struct {
21-
config configFlags
24+
config configFlags
25+
debugmode bool
2226
}
2327

2428
func integrateCmd() *cobra.Command {
@@ -43,9 +47,10 @@ func integrateVSCodeCmd() *cobra.Command {
4347
Hidden: true,
4448
Short: "Integrate devbox environment with VSCode.",
4549
RunE: func(cmd *cobra.Command, args []string) error {
46-
return runIntegrateVSCodeCmd(cmd)
50+
return runIntegrateVSCodeCmd(cmd, flags)
4751
},
4852
}
53+
command.Flags().BoolVar(&flags.debugmode, "debugmode", false, "enable debug outputs to a file.")
4954
flags.config.register(command)
5055

5156
return command
@@ -55,21 +60,27 @@ type parentMessage struct {
5560
ConfigDir string `json:"configDir"`
5661
}
5762

58-
func runIntegrateVSCodeCmd(cmd *cobra.Command) error {
63+
func runIntegrateVSCodeCmd(cmd *cobra.Command, flags integrateCmdFlags) error {
64+
dbug := debugMode{
65+
enabled: flags.debugmode,
66+
}
5967
// Setup process communication with node as parent
68+
dbug.logToFile("Devbox process initiated. Setting up communication channel with VSCode process")
6069
channel, err := go2node.RunAsNodeChild()
6170
if err != nil {
71+
dbug.logToFile(err.Error())
6272
return err
6373
}
64-
6574
// Get config dir as a message from parent process
6675
msg, err := channel.Read()
6776
if err != nil {
77+
dbug.logToFile(err.Error())
6878
return err
6979
}
7080
// Parse node process' message
7181
var message parentMessage
7282
if err = json.Unmarshal(msg.Message, &message); err != nil {
83+
dbug.logToFile(err.Error())
7384
return err
7485
}
7586

@@ -79,11 +90,14 @@ func runIntegrateVSCodeCmd(cmd *cobra.Command) error {
7990
Stderr: cmd.ErrOrStderr(),
8091
})
8192
if err != nil {
93+
dbug.logToFile(err.Error())
8294
return err
8395
}
8496
// Get env variables of a devbox shell
97+
dbug.logToFile("Computing devbox environment")
8598
envVars, err := box.EnvVars(cmd.Context())
8699
if err != nil {
100+
dbug.logToFile(err.Error())
87101
return err
88102
}
89103
envVars = slices.DeleteFunc(envVars, func(s string) bool {
@@ -96,10 +110,12 @@ func runIntegrateVSCodeCmd(cmd *cobra.Command) error {
96110
})
97111

98112
// Send message to parent process to terminate
113+
dbug.logToFile("Signaling VSCode to close")
99114
err = channel.Write(&go2node.NodeMessage{
100115
Message: []byte(`{"status": "finished"}`),
101116
})
102117
if err != nil {
118+
dbug.logToFile(err.Error())
103119
return err
104120
}
105121
// Open vscode with devbox shell environment
@@ -108,10 +124,34 @@ func runIntegrateVSCodeCmd(cmd *cobra.Command) error {
108124
var outb, errb bytes.Buffer
109125
cmnd.Stdout = &outb
110126
cmnd.Stderr = &errb
127+
dbug.logToFile("Re-opening VSCode in computed devbox environment")
111128
err = cmnd.Run()
112129
if err != nil {
113-
debug.Log("out: %s \n err: %s", outb.String(), errb.String())
130+
dbug.logToFile(fmt.Sprintf("stdout: %s \n stderr: %s", outb.String(), errb.String()))
131+
dbug.logToFile(err.Error())
114132
return err
115133
}
116134
return nil
117135
}
136+
137+
type debugMode struct {
138+
enabled bool
139+
}
140+
141+
func (d *debugMode) logToFile(msg string) {
142+
// only write to file when --debugmode=true flag is passed
143+
if d.enabled {
144+
file, err := os.OpenFile(".devbox/extension.log", os.O_APPEND|os.O_WRONLY, 0o666)
145+
if err != nil {
146+
log.Fatal(err)
147+
}
148+
timestamp := time.Now().UTC().Format(time.RFC1123)
149+
_, err = file.WriteString("[" + timestamp + "] " + msg + "\n")
150+
if err != nil {
151+
log.Fatal(err)
152+
}
153+
if err = file.Close(); err != nil {
154+
log.Fatal(err)
155+
}
156+
}
157+
}

vscode-extension/package.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,11 @@
128128
"type": "boolean",
129129
"default": true,
130130
"description": "Automatically run devbox shell when terminal is opened."
131+
},
132+
"devbox.enableDebugMode": {
133+
"type": "boolean",
134+
"default": false,
135+
"description": "Enables debug mode for this extension which creates an extension.log in .devbox/ directory. Currently only works for 'Devbox: Reopen in Devbox shell environment' command."
131136
}
132137
}
133138
}

vscode-extension/src/devbox.ts

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { window, workspace, commands, ProgressLocation, Uri, ConfigurationTarget, env } from 'vscode';
2+
import { writeFile, open } from 'fs/promises';
23
import { spawn, spawnSync } from 'node:child_process';
34

45

@@ -32,25 +33,30 @@ export async function devboxReopen() {
3233
if (workspace.workspaceFolders) {
3334
const workingDir = workspace.workspaceFolders[0].uri;
3435
const dotdevbox = Uri.joinPath(workingDir, '/.devbox');
36+
await logToFile(dotdevbox, 'Installing devbox packages');
3537
progress.report({ message: 'Installing devbox packages...', increment: 25 });
3638
await setupDotDevbox(workingDir, dotdevbox);
37-
39+
3840
// setup required vscode settings
41+
await logToFile(dotdevbox, 'Updating VSCode configurations');
3942
progress.report({ message: 'Updating configurations...', increment: 50 });
4043
updateVSCodeConf();
4144

4245
// Calling CLI to compute devbox env
46+
await logToFile(dotdevbox, 'Calling "devbox integrate" to setup environment');
4347
progress.report({ message: 'Calling Devbox to setup environment...', increment: 80 });
4448
// To use a custom compiled devbox when testing, change this to an absolute path.
4549
const devbox = 'devbox';
4650
// run devbox integrate and then close this window
47-
let child = spawn(devbox, ['integrate', 'vscode'], {
51+
const debugModeFlag = workspace.getConfiguration("devbox").get("enableDebugMode");
52+
let child = spawn(devbox, ['integrate', 'vscode', '--debugmode='+debugModeFlag], {
4853
cwd: workingDir.path,
4954
stdio: [0, 1, 2, 'ipc']
5055
});
5156
// if CLI closes before sending "finished" message
5257
child.on('close', (code: number) => {
5358
console.log("child process closed with exit code:", code);
59+
logToFile(dotdevbox, 'child process closed with exit code: ' + code);
5460
window.showErrorMessage("Failed to setup devbox environment.");
5561
reject();
5662
});
@@ -65,6 +71,7 @@ export async function devboxReopen() {
6571
}
6672
else {
6773
console.log(msg);
74+
logToFile(dotdevbox, 'Failed to setup devbox environment.' + String(msg));
6875
window.showErrorMessage("Failed to setup devbox environment.");
6976
reject();
7077
}
@@ -127,4 +134,21 @@ function updateVSCodeConf() {
127134
ConfigurationTarget.Workspace
128135
);
129136
}
130-
}
137+
}
138+
139+
async function logToFile(dotDevboxPath: Uri, message: string) {
140+
// only print to log file if debug mode config is set to true
141+
if (workspace.getConfiguration("devbox").get("enableDebugMode")){
142+
try {
143+
const logFilePath = Uri.joinPath(dotDevboxPath, 'extension.log');
144+
const timestamp = new Date().toUTCString();
145+
const fileHandler = await open(logFilePath.fsPath, 'a');
146+
const logData = new Uint8Array(Buffer.from(`[${timestamp}] ${message}\n`));
147+
await writeFile(fileHandler, logData, {flag: 'a'} );
148+
await fileHandler.close();
149+
} catch (error) {
150+
console.log("failed to write to extension.log file");
151+
console.error(error);
152+
}
153+
}
154+
}

0 commit comments

Comments
 (0)