예제 #1
0
func BeforeAPICall(app string, r *http.Request) {
	c := &Call{
		App:         app,
		Host:        hostname,
		RemoteAddr:  r.RemoteAddr,
		UserAgent:   r.UserAgent(),
		URL:         r.URL.String(),
		HTTPMethod:  r.Method,
		Route:       mux.CurrentRoute(r).GetName(),
		RouteParams: mapStringStringAsParams(mux.Vars(r)),
		QueryParams: mapStringSliceOfStringAsParams(r.URL.Query()),
		Start:       time.Now().In(time.UTC),
	}
	if parentCallID, ok := GetParentCallID(r); ok {
		c.ParentCallID = nnz.Int64(parentCallID)
	}
	if CurrentUser != nil {
		c.UID = nnz.Int(CurrentUser(r))
	}

	err := insertCall(c)
	if err != nil {
		log.Printf("insertCall failed: %s", err)
	}
	setCallID(r, c.ID)
}
예제 #2
0
// TrackAPICall wraps an API endpoint handler and records incoming API calls.
func TrackAPICall(h http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		c := &Call{
			URL:         r.URL.String(),
			Route:       mux.CurrentRoute(r).GetName(),
			RouteParams: mapStringStringAsParams(mux.Vars(r)),
			QueryParams: mapStringSliceOfStringAsParams(r.URL.Query()),
			Date:        time.Now(),
		}

		// Try to get the current view info from the X-Track-View header.
		viewID, err := GetViewID(r)
		if err != nil {
			log.Printf("GetViewID failed: %s", err)
			w.WriteHeader(http.StatusInternalServerError)
			return
		}
		if viewID != nil {
			c.Instance = viewID.Instance
			c.ViewSeq = nnz.Int(viewID.Seq)
		}

		// Otherwise, try to get the instance from the request context.
		if c.Instance == 0 {
			if i := GetInstance(r); i != 0 {
				c.Instance = i
			}
		}

		err = InsertCall(c)
		if err != nil {
			log.Printf("InsertCall failed: %s", err)
			w.WriteHeader(http.StatusInternalServerError)
			return
		}

		status := CallStatus{
			CallID:   c.ID,
			Panicked: true, // assume the worst, set false if no panic
		}
		start := time.Now()
		rw := newRecorder(w)
		defer func() {
			status.Duration = time.Since(start).Nanoseconds()
			status.BodyLength = rw.BodyLength
			status.HTTPStatusCode = rw.Code
			err := InsertCallStatus(&status)
			if err != nil {
				log.Printf("warn: UpdateCallStatus failed (ID=%d): %s", c.ID, err)
			}
		}()

		h.ServeHTTP(rw, r)

		status.Panicked = false
	})
}
예제 #3
0
func TestTrackAPICall_WithAssociatedView(t *testing.T) {
	dbSetUp()
	httpSetUp()
	defer dbTearDown()
	defer httpTearDown()

	wantViewID := &ViewID{Instance: 123, Seq: 456}
	var called bool
	h := TrackAPICall(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		called = true
		viewID, err := GetViewID(r)
		if err != nil {
			t.Fatal("GetViewID", err)
		}
		if !reflect.DeepEqual(wantViewID, viewID) {
			t.Errorf("want viewID == %+v, got %+v", wantViewID, viewID)
		}
	}))

	rt := mux.NewRouter()
	rt.Path(`/`).Methods("GET").Handler(h)
	rootMux.Handle("/", rt)

	wantCall := &Call{Instance: wantViewID.Instance, ViewSeq: nnz.Int(wantViewID.Seq)}

	httpGet(t, serverURL.String(), ViewIDHeader, makeViewIDHeader(*wantViewID))

	// Check that call was tracked.
	if !called {
		t.Errorf("!called")
	}
	call := getOnlyOneCall(t)
	if !reflect.DeepEqual(wantCall.ViewID(), call.ViewID()) {
		t.Errorf("want call.View == %+v, got %+v", wantCall.ViewID(), call.ViewID())
	}
}