authorgravatar for me@t3.ggTheo Browne <me@t3.gg> 2026-09-25 19:14:32-07:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2026-09-25 19:14:32-07:00
log20885cecf77e205b8931ca1b29f0a2832836a157
treef289915947a008e0af0fba18d9fd878a0fdca0f5
parent5660ab5cb55633a1657e715b0af9bd1e449c8a63
signature Signed by PGP key B5690EEEBB952194

feat(observability): name the command on subprocess spans (#13701)

Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

2 files changed, 12 insertions(+), 0 deletions(-)

apps/server/src/processRunner.test.ts+8
...@@ -412,3 +412,11 @@ describe("isWindowsCommandNotFound", () => {...@@ -412,3 +412,11 @@ describe("isWindowsCommandNotFound", () => {
412 }),412 }),
413 );413 );
414});414});
415
416describe("commandName", () => {
417 it("drops the directory from POSIX and Windows paths", () => {
418 expect(ProcessRunner.commandName("/Users/me/.local/bin/claude")).toBe("claude");
419 expect(ProcessRunner.commandName("C:\\Program Files\\nodejs\\npx.cmd")).toBe("npx.cmd");
420 expect(ProcessRunner.commandName("git")).toBe("git");
421 });
422});
apps/server/src/processRunner.ts+4
...@@ -285,10 +285,14 @@ function finalizeRunProcess<R>(...@@ -285,10 +285,14 @@ function finalizeRunProcess<R>(
285 );285 );
286}286}
287287
288/** The executable name without its directory, recorded as `process.command` on process spans. */
289export const commandName = (command: string) => command.replace(/^.*[\\/]/, "");
290
288const runProcessCore = Effect.fn("processRunner.runProcessCore")(function* (291const runProcessCore = Effect.fn("processRunner.runProcessCore")(function* (
289 spawner: ChildProcessSpawner.ChildProcessSpawner["Service"],292 spawner: ChildProcessSpawner.ChildProcessSpawner["Service"],
290 input: ProcessRunInput,293 input: ProcessRunInput,
291): Effect.fn.Return<ProcessRunOutput, ProcessRunError, Scope.Scope> {294): Effect.fn.Return<ProcessRunOutput, ProcessRunError, Scope.Scope> {
295 yield* Effect.annotateCurrentSpan("process.command", commandName(input.command));
292 const maxOutputBytes = input.maxOutputBytes ?? DEFAULT_MAX_OUTPUT_BYTES;296 const maxOutputBytes = input.maxOutputBytes ?? DEFAULT_MAX_OUTPUT_BYTES;
293 const outputMode = input.outputMode ?? "error";297 const outputMode = input.outputMode ?? "error";
294 const truncatedMarker = input.truncatedMarker ?? "";298 const truncatedMarker = input.truncatedMarker ?? "";