Skip to content
This repository has been archived by the owner on Aug 31, 2023. It is now read-only.

Commit

Permalink
fix(rome_cli): improve the logging of panics and connection errors (#…
Browse files Browse the repository at this point in the history
…3957)

* fix(rome_cli): improve the logging of panics and connection errors

* improve the asynchronous handling of the CLI child process

* fix the formatting
  • Loading branch information
leops authored Dec 5, 2022
1 parent 1a944e2 commit 5cd4dfd
Show file tree
Hide file tree
Showing 2 changed files with 65 additions and 30 deletions.
8 changes: 7 additions & 1 deletion crates/rome_cli/src/panic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ pub fn setup_panic_handler() {
}

fn panic_handler(info: &PanicInfo) {
// Buffer the error message to a string before printing it to stderr at once
// Buffer the error message to a string before printing it at once
// to prevent it from getting mixed with other errors if multiple threads
// panic at the same time
let mut error = String::new();
Expand All @@ -37,5 +37,11 @@ fn panic_handler(info: &PanicInfo) {
writeln!(error, "Message: {msg}").unwrap();
}

// Write the panic to stderr
eprintln!("{error}");

// Write the panic to the log file, this is done last since the `tracing`
// infrastructure could panic a second time and abort the process, so we
// want to ensure the error has at least been logged to stderr beforehand
tracing::error!("{error}");
}
87 changes: 58 additions & 29 deletions editors/vscode/src/main.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { spawn } from "child_process";
import { connect } from "net";
import type { Readable } from "stream";
import { connect, type Socket } from "net";
import { promisify } from "util";
import {
ExtensionContext,
Expand Down Expand Up @@ -247,52 +248,80 @@ async function fileExists(path: Uri) {
}
}

function getSocket(
function collectStream(stream: Readable) {
return new Promise<string>((resolve, reject) => {
let buffer = "";
stream.on("data", (data) => {
buffer += data.toString("utf-8");
});

stream.on("error", reject);
stream.on("end", () => {
resolve(buffer);
});
});
}

async function getSocket(
outputChannel: OutputChannel,
command: string,
): Promise<string> {
return new Promise((resolve, reject) => {
const process = spawn(command, ["__print_socket"], {
stdio: "pipe",
});
const process = spawn(command, ["__print_socket"], {
stdio: "pipe",
});

const exitCode = new Promise<number>((resolve, reject) => {
process.on("error", reject);
process.on("exit", resolve);
});

let output = "";
process.stdout.on("data", (data) => {
output += data.toString("utf-8");
});
const [stdout, stderr, code] = await Promise.all([
collectStream(process.stdout),
collectStream(process.stderr),
exitCode,
]);

process.on("exit", (code) => {
if (code === 0) {
const pipeName = output.trimEnd();
outputChannel.appendLine(`Connecting to "${pipeName}" ...`);
resolve(pipeName);
} else {
reject(code);
}
});
});
const pipeName = stdout.trimEnd();

if (code !== 0 || pipeName.length === 0) {
let message = `Command "${command} __print_socket" exited with code ${code}`;
if (stderr.length > 0) {
message += `\nOutput:\n${stderr}`;
}

throw new Error(message);
} else {
outputChannel.appendLine(`Connecting to "${pipeName}" ...`);
return pipeName;
}
}

function wrapConnectionError(err: Error, path: string): Error {
return Object.assign(
new Error(
`Could not connect to the Rome server at "${path}": ${err.message}`,
),
{ name: err.name, stack: err.stack },
);
}

async function createMessageTransports(
outputChannel: OutputChannel,
command: string,
): Promise<StreamInfo> {
const path = await getSocket(outputChannel, command);
const socket = connect(path);

let socket: Socket;
try {
socket = connect(path);
} catch (err) {
throw wrapConnectionError(err, path);
}

await new Promise((resolve, reject) => {
socket.once("ready", resolve);
socket.once("error", (err) => {
reject(
Object.assign(
new Error(
`Could not connect to the Rome server at "${path}": ${err.message}`,
),
{ name: err.name, stack: err.stack },
),
);
reject(wrapConnectionError(err, path));
});
});

Expand Down

0 comments on commit 5cd4dfd

Please sign in to comment.