func (r *Reporter) Init(c *client.Config) { reporters := strings.Split(reporterDestinations, ":") for _, rep := range reporters { newRep, err := reporter.Get(rep) if err != nil { if sentryClient := sentry.GetClient(); sentryClient != nil { sentryClient.CaptureError(err, map[string]string{}) } // Allow other reporters to proceed continue } if newRep != nil { log.Printf("[multireporter] Initialization successful: %s", rep) r.reporterDestinations = append(r.reporterDestinations, newRep) } } log.Printf("[multireporter] Setting up multiple client reporters: %s\n", reporters) for _, rep := range r.reporterDestinations { rep.Init(c) } }
// Utility method for sending a payload. This wraps httpPost in a framework // nicer for the Reporter itself, as it turns the ReportPayload into its // associated params (which corresponds to its data). We also attempt // httpPost multiple times in order to account for flakiness in the // network connection. This function is synchronous. func sendPayload(r *Reporter, rp ReportPayload) { var ( resp *http.Response err error status string ) path := r.publishUri + rp.path if rp.data == nil { rp.data = make(map[string]string) } rp.data["date"] = time.Now().UTC().Format("2006-01-02T15:04:05.0Z") for tryCnt := 1; tryCnt <= numPublishRetries; tryCnt++ { log.Printf("[reporter] POST %s try: %d", path, tryCnt) resp, err = httpPost(path, rp.data, rp.filename) if resp != nil { status = resp.Status } else { status = "-1" } if resp != nil && resp.StatusCode/100 == 2 { break } var errmsg string if err != nil { errmsg = err.Error() } else { // If there wasn't an IO error, use the response body as the error message. var bodyData bytes.Buffer if _, e := bodyData.ReadFrom(resp.Body); e != nil { log.Printf("[reporter] Error reading POST %s response body: %s", path, e) } errmsg = bodyData.String() } log.Printf("[reporter] POST %s failed, try: %d, resp: %s, err: %s", path, tryCnt, status, errmsg) /* We are unable to publish to the endpoint. * Fail fast and let the above layers handle the outage */ if tryCnt == numPublishRetries { const msg = "Couldn't to connect to publish endpoint" if client := sentry.GetClient(); client != nil { client.CaptureMessageAndWait(msg, nil) } // TODO: Report an infra failure rather than panicing. panic(msg) } log.Printf("[reporter] Sleep for %d ms", backoffTimeMs) time.Sleep(time.Duration(backoffTimeMs) * time.Millisecond) } }
// Returns whether run was successful. func run() bool { var sentryClient *raven.Client if sentryClient = sentry.GetClient(); sentryClient != nil { log.Printf("Using Sentry; ProjectID=%s, URL=%s", sentryClient.ProjectID(), sentryClient.URL()) // Don't return until we're finished sending to Sentry. defer sentryClient.Wait() // Ensure main thread panics are caught and reported. defer func() { if p := recover(); p != nil { var err error switch rval := p.(type) { case error: err = rval default: err = errors.New(fmt.Sprint(rval)) } packet := raven.NewPacket(err.Error(), raven.NewException(err, raven.NewStacktrace(2, 3, nil))) log.Printf("[client] Sending panic to Sentry") _, ch := sentryClient.Capture(packet, map[string]string{}) if serr := <-ch; serr != nil { log.Printf("SENTRY ERROR: %s", serr) } panic(p) } }() } else { log.Println("Sentry NOT ENABLED.") } // Error handling in place; now we begin. config, err := client.GetConfig() if err != nil { panic(err) } if sentryClient != nil { sentryClient.SetTagsContext(map[string]string{ "projectslug": config.Project.Slug, "jobstep_id": config.JobstepID, }) } result, err := engine.RunBuildPlan(config) log.Printf("[client] Finished: %s", result) if err != nil { log.Printf("[client] error: %s", err) sentry.Error(err, map[string]string{}) } return err == nil && result == engine.RESULT_PASSED }
// Returns whether run was successful. func run() bool { if sentryClient := sentry.GetClient(); sentryClient != nil { // Don't return until we're finished sending to Sentry. defer sentryClient.Wait() // Ensure main thread panics are caught and reported. defer func() { if p := recover(); p != nil { var err error switch rval := p.(type) { case error: err = rval default: err = errors.New(fmt.Sprint(rval)) } packet := raven.NewPacket(err.Error(), raven.NewException(err, raven.NewStacktrace(2, 3, nil))) log.Printf("[client] Sending panic to Sentry") _, ch := sentryClient.Capture(packet, map[string]string{}) <-ch panic(p) } }() } // Error handling in place; now we begin. config, err := client.GetConfig() if err != nil { panic(err) } result, err := engine.RunBuildPlan(config) log.Printf("[client] Finished: %s", result) if err != nil { log.Printf("[client] error: %s", err) sentry.Error(err, nil) } return err == nil && result == engine.RESULT_PASSED }