func sampleData(c appdash.Collector) error { const numTraces = 60 log.Printf("Adding sample data (%d traces)", numTraces) for i := appdash.ID(1); i <= numTraces; i++ { traceID := appdash.NewRootSpanID() traceRec := appdash.NewRecorder(traceID, c) traceRec.Name(fakeHosts[rand.Intn(len(fakeHosts))]) // A random length for the trace. length := time.Duration(rand.Intn(1000)) * time.Millisecond startTime := time.Now().Add(-time.Duration(rand.Intn(100)) * time.Minute) traceRec.Event(&sqltrace.SQLEvent{ ClientSend: startTime, ClientRecv: startTime.Add(length), SQL: "SELECT * FROM table_name;", Tag: fmt.Sprintf("fakeTag%d", rand.Intn(10)), }) // We'll split the trace into N (3-7) spans (i.e. "N operations") each with // a random duration of time adding up to the length of the trace. numSpans := rand.Intn(7-3) + 3 times := randomSplit(int(length/time.Millisecond), numSpans) lastSpanID := traceID for j := 1; j <= numSpans; j++ { // The parent span is the predecessor. spanID := appdash.NewSpanID(lastSpanID) rec := appdash.NewRecorder(spanID, c) rec.Name(fakeNames[(j+int(i))%len(fakeNames)]) if j%3 == 0 { rec.Log("hello") } if j%5 == 0 { rec.Msg("hi") } // Generate a span event. spanDuration := time.Duration(times[j-1]) * time.Millisecond rec.Event(&sqltrace.SQLEvent{ ClientSend: startTime, ClientRecv: startTime.Add(spanDuration), SQL: "SELECT * FROM table_name;", Tag: fmt.Sprintf("fakeTag%d", rand.Intn(10)), }) // Shift the start time forward. startTime = startTime.Add(spanDuration) // Check for any recorder errors. if errs := rec.Errors(); len(errs) > 0 { return fmt.Errorf("recorder errors: %v", errs) } lastSpanID = spanID } } return nil }
func getSpanID(h http.Header) (spanID *appdash.SpanID, fromHeader string, err error) { // Check for Span-ID. fromHeader = HeaderSpanID spanID, err = getSpanIDHeader(h, HeaderSpanID) if err != nil { return nil, fromHeader, err } // Check for Parent-Span-ID. if spanID == nil { fromHeader = HeaderParentSpanID spanID, err = getSpanIDHeader(h, HeaderParentSpanID) if err != nil { return nil, fromHeader, err } if spanID != nil { newSpanID := appdash.NewSpanID(*spanID) spanID = &newSpanID } } // Create a new root span ID. if spanID == nil { fromHeader = "" newSpanID := appdash.NewRootSpanID() spanID = &newSpanID } return spanID, fromHeader, nil }
// RoundTrip implements the RoundTripper interface. func (t *Transport) RoundTrip(original *http.Request) (*http.Response, error) { // To set extra querystring params, we must make a copy of the Request so // that we don't modify the Request we were given. This is required by the // specification of http.RoundTripper. req := cloneRequest(original) t.setCloneRequest(original, req) defer t.setCloneRequest(original, nil) child := t.Recorder.Child() if t.SetName { child.Name("Request " + req.URL.Host) } // New child span is created and set as HTTP header instead of using `child` // in order to have a single span recording operation per httptrace event // (HTTPClient or HTTPServer). span := appdash.NewSpanID(t.Recorder.SpanID) SetSpanIDHeader(req.Header, span) e := NewClientEvent(req) e.ClientSend = time.Now() // Make the HTTP request. transport := t.getTransport() resp, err := transport.RoundTrip(req) e.ClientRecv = time.Now() if err == nil { e.Response = responseInfo(resp) } else { e.Response.StatusCode = -1 } child.Event(e) child.Finish() return resp, err }