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) }
// 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 }) }
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()) } }