Skip to content

Commit b9d1d31

Browse files
authored
fix: capture exit code (#39)
Capture exit code, so that the user can use that info to debug why the spawned command is failing.
1 parent 79bcaff commit b9d1d31

File tree

8 files changed

+32
-21
lines changed

8 files changed

+32
-21
lines changed

cmd/exec.go

+12-5
Original file line numberDiff line numberDiff line change
@@ -33,14 +33,20 @@ func execCmd() *ffcli.Command {
3333
return fmt.Errorf("at least one argument is required")
3434
}
3535

36-
cmdError, err := exec.Exec(args, exec.ExecCfg{
36+
l, err := logrus.ParseLevel(*logLevel)
37+
if err != nil {
38+
return fmt.Errorf("parsing log level: %w", err)
39+
}
40+
logger := logrus.New()
41+
logger.SetLevel(l)
42+
43+
cmdError, err := exec.Exec(logger, args, exec.ExecCfg{
3744
OutputDir: *outputDir,
3845
APIKey: *apiKey,
3946
ServerAddress: *cloudServerAddress,
4047
CommitSHA: *commitSHA,
4148
UploadToCloud: *uploadToCloud,
4249
Branch: *branch,
43-
LogLevel: *logLevel,
4450
Export: *exportLocally,
4551
UploadToPublicAPI: *uploadToPublicAPI,
4652
})
@@ -50,11 +56,12 @@ func execCmd() *ffcli.Command {
5056
return err
5157
}
5258

53-
// Add additional context, since it may be weird to just see "exit eror code X"
5459
if cmdError != nil {
55-
logrus.Error("error in spawned command")
60+
// Add additional context, since it may be weird to just see "exit eror code X"
61+
return fmt.Errorf("error in spawned command: %w", cmdError)
5662
}
57-
return cmdError
63+
64+
return nil
5865
},
5966
}
6067
}

examples/go/testscript.txtar

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
pyroscope-ci go install --applicationName=myapp .
2-
pyroscope-ci exec --uploadToCloud=false --exportLocally -- docker run -v $WORK:/app --link $PYROSCOPE_PROXY_ADDRESS --env PYROSCOPE_ADHOC_SERVER_ADDRESS $IMAGE_NAME sh -c 'go test ./... -v'
2+
pyroscope-ci exec --logLevel=debug --uploadToCloud=false --exportLocally -- docker run -v $WORK:/app --link $PYROSCOPE_PROXY_ADDRESS --env PYROSCOPE_ADHOC_SERVER_ADDRESS $IMAGE_NAME sh -c 'go test ./... -v'
33

44
exists pyroscope-ci-output/myapp.cpu.json
55
exists pyroscope-ci-output/myapp.goroutines.json

examples/nodejs/jest/testscript.txtar

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
1-
pyroscope-ci exec --uploadToCloud=false --exportLocally -- docker run --link $PYROSCOPE_PROXY_ADDRESS --env PYROSCOPE_ADHOC_SERVER_ADDRESS $IMAGE_NAME yarn test
1+
pyroscope-ci exec --logLevel=debug --uploadToCloud=false --exportLocally -- docker run --link $PYROSCOPE_PROXY_ADDRESS --env PYROSCOPE_ADHOC_SERVER_ADDRESS $IMAGE_NAME yarn test
22
exists pyroscope-ci-output/pyroscope.tests.cpu.json
+1-1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
1-
pyroscope-ci exec --uploadToCloud=false --exportLocally -- docker run --link $PYROSCOPE_PROXY_ADDRESS --env PYROSCOPE_ADHOC_SERVER_ADDRESS $IMAGE_NAME yarn test
1+
pyroscope-ci exec --logLevel=debug --uploadToCloud=false --exportLocally -- docker run --link $PYROSCOPE_PROXY_ADDRESS --env PYROSCOPE_ADHOC_SERVER_ADDRESS $IMAGE_NAME yarn test
22
exists pyroscope-ci-output/example-mocha.cpu.json
33

examples/ruby/rspec/testscripts.txtar

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
1-
pyroscope-ci exec --uploadToCloud=false --exportLocally -- docker run --link $PYROSCOPE_PROXY_ADDRESS --env PYROSCOPE_ADHOC_SERVER_ADDRESS $IMAGE_NAME ./bin/rspec
1+
pyroscope-ci exec --logLevel=debug --uploadToCloud=false --exportLocally -- docker run --link $PYROSCOPE_PROXY_ADDRESS --env PYROSCOPE_ADHOC_SERVER_ADDRESS $IMAGE_NAME ./bin/rspec
22
exists pyroscope-ci-output/ruby.tests.cpu.json
33

internal/exec/exec.go

+3-8
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@ type ExecCfg struct {
1919
UploadToCloud bool
2020
Export bool
2121
UploadToPublicAPI bool
22-
LogLevel string
2322
}
2423

2524
// Exec executes a program and exports its captured profiles
@@ -34,11 +33,7 @@ type ExecCfg struct {
3433
// Notice that it returns 2 different errors:
3534
// cmdError refers to the error of the command exec'd
3635
// and err to any other error
37-
func Exec(args []string, cfg ExecCfg) (cmdError error, err error) {
38-
logger := logrus.StandardLogger()
39-
lvl, _ := logrus.ParseLevel(cfg.LogLevel)
40-
logger.SetLevel(lvl)
41-
36+
func Exec(logger *logrus.Logger, args []string, cfg ExecCfg) (cmdError error, err error) {
4237
runner := NewRunner(logger)
4338

4439
if !cfg.Export && !cfg.UploadToCloud && !cfg.UploadToPublicAPI {
@@ -48,8 +43,8 @@ func Exec(args []string, cfg ExecCfg) (cmdError error, err error) {
4843

4944
logger.Debug("exec'ing command")
5045
ingestedItems, duration, cmdError := runner.Run(args)
51-
if err != nil {
52-
logger.Errorf("process errored: %s. will still try to upload ingested data", err)
46+
if cmdError != nil {
47+
logger.Debug("process errored. will still try to upload ingested data", cmdError)
5348
}
5449

5550
if len(ingestedItems) <= 0 {

internal/exec/exec_test.go

+6-3
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,17 @@
11
package exec_test
22

33
import (
4+
"io"
45
"os"
56
"testing"
67

78
"github.com/pyroscope-io/ci/internal/exec"
9+
"github.com/sirupsen/logrus"
810
)
911

1012
func TestCapturingCmdError(t *testing.T) {
13+
noopLogger := logrus.New()
14+
noopLogger.SetOutput(io.Discard)
1115
dir, err := os.MkdirTemp("", "")
1216
if err != nil {
1317
t.Fatal(err)
@@ -16,7 +20,7 @@ func TestCapturingCmdError(t *testing.T) {
1620

1721
// Running an unknown command, we should get back an error
1822
cfg := exec.ExecCfg{UploadToCloud: true, Export: true, OutputDir: dir}
19-
cmdError, err := exec.Exec([]string{"unknown command"}, cfg)
23+
cmdError, err := exec.Exec(noopLogger, []string{"unknown-command"}, cfg)
2024
if err != nil {
2125
t.Error("did not expect error to happen")
2226
}
@@ -27,13 +31,12 @@ func TestCapturingCmdError(t *testing.T) {
2731

2832
// Running a valid
2933
// TODO: what command would be valid cross os?
30-
cmdError, err = exec.Exec([]string{"echo"}, cfg)
34+
cmdError, err = exec.Exec(noopLogger, []string{"echo"}, cfg)
3135
if err != nil {
3236
t.Error("did not expect error to happen")
3337
}
3438

3539
if cmdError != nil {
3640
t.Error("expected cmdError to NOT have happened")
3741
}
38-
3942
}

internal/exec/runner.go

+7-1
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,13 @@ func (p *Runner) Run(args []string) (map[string]flamebearer.FlamebearerProfile,
9696
case <-ticker.C:
9797
if !process.Exists(cmd.Process.Pid) {
9898
logrus.Debug("child process exited")
99-
return p.ingester.GetIngestedItems(), captureDuration(), cmd.Wait()
99+
err := cmd.Wait()
100+
101+
if exiterr, ok := err.(*osExec.ExitError); ok {
102+
err = fmt.Errorf("exit code %d: %v", exiterr.ExitCode(), err)
103+
}
104+
105+
return p.ingester.GetIngestedItems(), captureDuration(), err
100106
}
101107
}
102108
}

0 commit comments

Comments
 (0)