diff --git a/exporter/stackdriver/stackdriver.go b/exporter/stackdriver/stackdriver.go index a8ae03c594a..001cdb0e1b6 100644 --- a/exporter/stackdriver/stackdriver.go +++ b/exporter/stackdriver/stackdriver.go @@ -25,6 +25,7 @@ import ( "context" "errors" "fmt" + "log" "time" traceapi "cloud.google.com/go/trace/apiv2" @@ -135,3 +136,11 @@ func (e *Exporter) Flush() { e.statsExporter.Flush() e.traceExporter.Flush() } + +func (o Options) handleError(err error) { + if o.OnError != nil { + o.OnError(err) + return + } + log.Printf("Error exporting to Stackdriver: %v", err) +} diff --git a/exporter/stackdriver/stackdriver_test.go b/exporter/stackdriver/stackdriver_test.go index 5b5020ae7f8..bcc182ae351 100644 --- a/exporter/stackdriver/stackdriver_test.go +++ b/exporter/stackdriver/stackdriver_test.go @@ -36,7 +36,11 @@ func TestExport(t *testing.T) { t.Skip("STACKDRIVER_TEST_PROJECT_ID not set") } - exporter, err := NewExporter(Options{ProjectID: projectID}) + var exportErrors []error + + exporter, err := NewExporter(Options{ProjectID: projectID, OnError: func(err error) { + exportErrors = append(exportErrors, err) + }}) if err != nil { t.Fatal(err) } @@ -56,7 +60,16 @@ func TestExport(t *testing.T) { // Test HTTP spans handler := http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) { + + _, backgroundSpan := trace.StartSpan(context.Background(), "BackgroundWork") + spanContext := backgroundSpan.SpanContext() + time.Sleep(10 * time.Millisecond) + backgroundSpan.End() + + _, span := trace.StartSpan(req.Context(), "Sleep") + span.AddLink(trace.Link{Type: trace.LinkTypeChild, TraceID: spanContext.TraceID, SpanID: spanContext.SpanID}) time.Sleep(150 * time.Millisecond) // do work + span.End() rw.Write([]byte("Hello, world!")) }) server := httptest.NewServer(&ochttp.Handler{Handler: handler}) @@ -81,6 +94,10 @@ func TestExport(t *testing.T) { // Flush twice to expose issue of exporter creating traces internally (#557) exporter.Flush() exporter.Flush() + + for _, err := range exportErrors { + t.Error(err) + } } func TestGRPC(t *testing.T) { diff --git a/exporter/stackdriver/stats.go b/exporter/stackdriver/stats.go index 8d0f16e5fd4..7b96c02a0fa 100644 --- a/exporter/stackdriver/stats.go +++ b/exporter/stackdriver/stats.go @@ -18,7 +18,6 @@ import ( "context" "errors" "fmt" - "log" "os" "path" "strconv" @@ -123,9 +122,9 @@ func (e *statsExporter) ExportView(vd *view.Data) { case bundler.ErrOversizedItem: go e.handleUpload(vd) case bundler.ErrOverflow: - e.onError(errors.New("failed to upload: buffer full")) + e.o.handleError(errors.New("failed to upload: buffer full")) default: - e.onError(err) + e.o.handleError(err) } } @@ -143,7 +142,7 @@ func getTaskValue() string { // of Data, as well as error handling. func (e *statsExporter) handleUpload(vds ...*view.Data) { if err := e.uploadStats(vds); err != nil { - e.onError(err) + e.o.handleError(err) } } @@ -155,14 +154,6 @@ func (e *statsExporter) Flush() { e.bundler.Flush() } -func (e *statsExporter) onError(err error) { - if e.o.OnError != nil { - e.o.OnError(err) - return - } - log.Printf("Failed to export to Stackdriver Monitoring: %v", err) -} - func (e *statsExporter) uploadStats(vds []*view.Data) error { span := trace.NewSpan( "go.opencensus.io/exporter/stackdriver.uploadStats", diff --git a/exporter/stackdriver/trace.go b/exporter/stackdriver/trace.go index 5ade3825520..3b95cce75bd 100644 --- a/exporter/stackdriver/trace.go +++ b/exporter/stackdriver/trace.go @@ -31,6 +31,7 @@ import ( // Stackdriver. // type traceExporter struct { + o Options projectID string bundler *bundler.Bundler // uploadFn defaults to uploadSpans; it can be replaced for tests. @@ -53,6 +54,7 @@ func newTraceExporterWithClient(o Options, c *tracingclient.Client) *traceExport e := &traceExporter{ projectID: o.ProjectID, client: c, + o: o, } bundler := bundler.NewBundler((*trace.SpanData)(nil), func(bundle interface{}) { e.uploadFn(bundle.([]*trace.SpanData)) @@ -93,7 +95,7 @@ func (e *traceExporter) ExportSpan(s *trace.SpanData) { case bundler.ErrOverflow: e.overflowLogger.log() default: - log.Println("OpenCensus Stackdriver exporter: failed to upload span:", err) + e.o.handleError(err) } } @@ -123,8 +125,7 @@ func (e *traceExporter) uploadSpans(spans []*trace.SpanData) { err := e.client.BatchWriteSpans(ctx, &req) if err != nil { span.SetStatus(trace.Status{Code: 2, Message: err.Error()}) - // TODO: Allow configuring a logger for exporters. - log.Printf("OpenCensus Stackdriver exporter: failed to upload %d spans: %v", len(spans), err) + e.o.handleError(err) } }