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", () => {
412412 }),
413413 );
414414});
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>(
285285 );
286286}
287287
288/** The executable name without its directory, recorded as `process.command` on process spans. */
289export const commandName = (command: string) => command.replace(/^.*[\\/]/, "");
290
288291const runProcessCore = Effect.fn("processRunner.runProcessCore")(function* (
289292 spawner: ChildProcessSpawner.ChildProcessSpawner["Service"],
290293 input: ProcessRunInput,
291294): Effect.fn.Return<ProcessRunOutput, ProcessRunError, Scope.Scope> {
295 yield* Effect.annotateCurrentSpan("process.command", commandName(input.command));
292296 const maxOutputBytes = input.maxOutputBytes ?? DEFAULT_MAX_OUTPUT_BYTES;
293297 const outputMode = input.outputMode ?? "error";
294298 const truncatedMarker = input.truncatedMarker ?? "";