MCPcopy
hub / github.com/cli/cli / SpawnSendTelemetry

Function SpawnSendTelemetry

internal/telemetry/telemetry.go:362–415  ·  view source on GitHub ↗

SpawnSendTelemetry spawns a detached subprocess to send telemetry. The payload is written to the child's stdin via a pipe so that it is not visible to other users through process argument inspection (e.g. ps aux). The parent writes the full payload and closes the pipe before returning, so no long-li

(executable string, payload SendTelemetryPayload)

Source from the content-addressed store, hash-verified

360//
361// All errors are silently ignored since telemetry is best-effort.
362func SpawnSendTelemetry(executable string, payload SendTelemetryPayload) {
363 payloadBytes, err := json.Marshal(payload)
364 if err != nil {
365 return
366 }
367
368 if len(payloadBytes) > maxPayloadSize {
369 return
370 }
371
372 // Resolve the executable to an absolute path before changing the child's
373 // working directory. Without this, a relative path (e.g. from GH_PATH) would
374 // be resolved against cmd.Dir at Start time and fail to spawn.
375 if abs, err := filepath.Abs(executable); err == nil {
376 executable = abs
377 }
378
379 cmd := exec.Command(executable, "send-telemetry")
380
381 cmd.Stdout = io.Discard
382 cmd.Stderr = io.Discard
383
384 // Set the working directory to a stable directory elsewhere so that the subprocess doesn't
385 // hold a reference to the parent's current working directory, avoiding any weirdness around
386 // deleting the parent process's current working directory while the child is still running.
387 // Only do this when we have an absolute executable path so that the child can still be found.
388 if filepath.IsAbs(executable) {
389 cmd.Dir = os.TempDir()
390 }
391
392 // Configure the child process to be detached from the parent so that it can continue running
393 // after the parent exits, and so that it doesn't receive any signals sent to the parent.
394 cmd.SysProcAttr = detachAttrs()
395
396 // Get the write end of the stdin pipe before starting.
397 stdin, err := cmd.StdinPipe()
398 if err != nil {
399 return
400 }
401
402 if err := cmd.Start(); err != nil {
403 _ = stdin.Close()
404 return
405 }
406
407 // Write the payload synchronously into the kernel pipe buffer, then close
408 // the pipe to signal EOF. The child reads the complete payload from stdin.
409 // io.Copy loops until all bytes are written, avoiding any risk of a short write.
410 _, _ = io.Copy(stdin, bytes.NewReader(payloadBytes))
411 _ = stdin.Close()
412
413 // Release resources associated with the child process since we will never Wait for it.
414 _ = cmd.Process.Release()
415}
416
417type NoOpService struct{}
418

Calls 4

CommandMethod · 0.80
detachAttrsFunction · 0.70
CloseMethod · 0.65
CopyMethod · 0.45