X Tutup
Skip to content

Commit f5293e1

Browse files
committed
Crash reporting shouldn't be static
Signed-off-by: David Gageot <david@gageot.net>
1 parent cd9301e commit f5293e1

File tree

4 files changed

+73
-41
lines changed

4 files changed

+73
-41
lines changed

commands/commands.go

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -103,8 +103,6 @@ func fatalOnError(command func(commandLine CommandLine, api libmachine.API) erro
103103
api.GithubAPIToken = context.GlobalString("github-api-token")
104104
api.Filestore.Path = context.GlobalString("storage-path")
105105

106-
crashreport.Configure(context.GlobalString("bugsnag-api-token"))
107-
108106
// TODO (nathanleclaire): These should ultimately be accessed
109107
// through the libmachine client by the rest of the code and
110108
// not through their respective modules. For now, however,
@@ -116,6 +114,11 @@ func fatalOnError(command func(commandLine CommandLine, api libmachine.API) erro
116114

117115
if err := command(&contextCommandLine{context}, api); err != nil {
118116
log.Fatal(err)
117+
118+
if crashErr, ok := err.(crashreport.CrashError); ok {
119+
crashReporter := crashreport.NewCrashReporter(mcndirs.GetBaseDir(), context.GlobalString("bugsnag-api-token"))
120+
crashReporter.Send(crashErr)
121+
}
119122
}
120123
}
121124
}

libmachine/crashreport/crash_report.go

Lines changed: 44 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@ import (
1616
"io/ioutil"
1717

1818
"github.com/bugsnag/bugsnag-go"
19-
"github.com/docker/machine/commands/mcndirs"
2019
"github.com/docker/machine/libmachine/log"
2120
"github.com/docker/machine/libmachine/mcnutils"
2221
"github.com/docker/machine/version"
@@ -27,28 +26,53 @@ const (
2726
noreportAPIKey = "no-report"
2827
)
2928

30-
var apiKey string
29+
type CrashReporter interface {
30+
Send(err CrashError) error
31+
}
32+
33+
// CrashError describes an error that should be reported to bugsnag
34+
type CrashError struct {
35+
Cause error
36+
Command string
37+
Context string
38+
DriverName string
39+
LogFilePath string
40+
}
3141

32-
// Configure the apikey for bugnag
33-
func Configure(key string) {
34-
apiKey = defaultAPIKey
35-
if key != "" {
36-
apiKey = key
42+
func (e CrashError) Error() string {
43+
return e.Cause.Error()
44+
}
45+
46+
type BugsnagCrashReporter struct {
47+
baseDir string
48+
apiKey string
49+
}
50+
51+
// NewCrashReporter creates a new bugsnag based CrashReporter. Needs an apiKey.
52+
func NewCrashReporter(baseDir string, apiKey string) *BugsnagCrashReporter {
53+
if apiKey == "" {
54+
apiKey = defaultAPIKey
55+
}
56+
57+
return &BugsnagCrashReporter{
58+
baseDir: baseDir,
59+
apiKey: apiKey,
3760
}
3861
}
3962

40-
func SendWithFile(err error, context string, driverName string, command string, path string) error {
41-
if noReportFileExist() || apiKey == noreportAPIKey {
63+
// Send sends a crash report to bugsnag via an http call.
64+
func (r *BugsnagCrashReporter) Send(err CrashError) error {
65+
if r.noReportFileExist() || r.apiKey == noreportAPIKey {
4266
log.Debug("Opting out of crash reporting.")
4367
return nil
4468
}
4569

46-
if apiKey == "" {
70+
if r.apiKey == "" {
4771
return errors.New("Not sending report since no api key has been set.")
4872
}
4973

5074
bugsnag.Configure(bugsnag.Configuration{
51-
APIKey: apiKey,
75+
APIKey: r.apiKey,
5276
// XXX we need to abuse bugsnag metrics to get the OS/ARCH information as a usable filter
5377
// Can do that with either "stage" or "hostname"
5478
ReleaseStage: fmt.Sprintf("%s (%s)", runtime.GOOS, runtime.GOARCH),
@@ -68,19 +92,23 @@ func SendWithFile(err error, context string, driverName string, command string,
6892
detectRunningShell(&metaData)
6993
detectUname(&metaData)
7094
detectOSVersion(&metaData)
71-
addFile(path, &metaData)
95+
addFile(err.LogFilePath, &metaData)
7296

7397
var buffer bytes.Buffer
7498
for _, message := range log.History() {
7599
buffer.WriteString(message + "\n")
76100
}
77101
metaData.Add("history", "trace", buffer.String())
78-
return bugsnag.Notify(err, metaData, bugsnag.SeverityError, bugsnag.Context{String: context}, bugsnag.ErrorClass{Name: fmt.Sprintf("%s/%s", driverName, command)})
102+
103+
return bugsnag.Notify(err.Cause, metaData, bugsnag.SeverityError, bugsnag.Context{String: err.Context}, bugsnag.ErrorClass{Name: fmt.Sprintf("%s/%s", err.DriverName, err.Command)})
79104
}
80105

81-
// Send through http the crash report to bugsnag need a call to Configure(apiKey) before
82-
func Send(err error, context string, driverName string, command string) error {
83-
return SendWithFile(err, context, driverName, command, "")
106+
func (r *BugsnagCrashReporter) noReportFileExist() bool {
107+
optOutFilePath := filepath.Join(r.baseDir, "no-error-report")
108+
if _, err := os.Stat(optOutFilePath); os.IsNotExist(err) {
109+
return false
110+
}
111+
return true
84112
}
85113

86114
func addFile(path string, metaData *bugsnag.MetaData) {
@@ -97,14 +125,6 @@ func addFile(path string, metaData *bugsnag.MetaData) {
97125
metaData.Add("logfile", filepath.Base(path), string(data))
98126
}
99127

100-
func noReportFileExist() bool {
101-
optOutFilePath := filepath.Join(mcndirs.GetBaseDir(), "no-error-report")
102-
if _, err := os.Stat(optOutFilePath); os.IsNotExist(err) {
103-
return false
104-
}
105-
return true
106-
}
107-
108128
func detectRunningShell(metaData *bugsnag.MetaData) {
109129
shell := os.Getenv("SHELL")
110130
if shell != "" {

libmachine/host/host.go

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -146,14 +146,22 @@ func (h *Host) Upgrade() error {
146146

147147
provisioner, err := provision.DetectProvisioner(h.Driver)
148148
if err != nil {
149-
crashreport.Send(err, "provision.DetectProvisioner", h.Driver.DriverName(), "Upgrade")
150-
return err
149+
return crashreport.CrashError{
150+
Cause: err,
151+
Command: "Upgrade",
152+
Context: "provision.DetectProvisioner",
153+
DriverName: h.Driver.DriverName(),
154+
}
151155
}
152156

153157
log.Info("Upgrading docker...")
154158
if err := provisioner.Package("docker", pkgaction.Upgrade); err != nil {
155-
crashreport.Send(err, "provisioner.Package", h.Driver.DriverName(), "Upgrade")
156-
return err
159+
return crashreport.CrashError{
160+
Cause: err,
161+
Command: "Upgrade",
162+
Context: "provisioner.Package",
163+
DriverName: h.Driver.DriverName(),
164+
}
157165
}
158166

159167
log.Info("Restarting docker...")

libmachine/libmachine.go

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -132,8 +132,18 @@ func (api *Client) Create(h *host.Host) error {
132132
log.Info("Creating machine...")
133133

134134
if err := api.performCreate(h); err != nil {
135-
sendCrashReport(err, api, h)
136-
return err
135+
vBoxLog := ""
136+
if h.DriverName == "virtualbox" {
137+
vBoxLog = filepath.Join(api.GetMachinesDir(), h.Name, h.Name, "Logs", "VBox.log")
138+
}
139+
140+
return crashreport.CrashError{
141+
Cause: err,
142+
Command: "Create",
143+
Context: "api.performCreate",
144+
DriverName: h.DriverName,
145+
LogFilePath: vBoxLog,
146+
}
137147
}
138148

139149
log.Debug("Reticulating splines...")
@@ -185,15 +195,6 @@ func (api *Client) performCreate(h *host.Host) error {
185195
return nil
186196
}
187197

188-
func sendCrashReport(err error, api *Client, host *host.Host) {
189-
if host.DriverName == "virtualbox" {
190-
vboxlogPath := filepath.Join(api.GetMachinesDir(), host.Name, host.Name, "Logs", "VBox.log")
191-
crashreport.SendWithFile(err, "api.performCreate", host.DriverName, "Create", vboxlogPath)
192-
} else {
193-
crashreport.Send(err, "api.performCreate", host.DriverName, "Create")
194-
}
195-
}
196-
197198
func (api *Client) Close() error {
198199
return api.clientDriverFactory.Close()
199200
}

0 commit comments

Comments
 (0)
X Tutup