/* Wraps the given http.Handler ServerHTTP function Will provide accounting metrics for the http.Request / http.Response life-cycle */ func (ih *instrumentedHandler) ServeHTTP(rw http.ResponseWriter, req *http.Request) { requestId, err := uuid.ParseHex(req.Header.Get("X-CF-RequestID")) if err != nil { requestId, err = GenerateUuid() if err != nil { log.Printf("failed to generated request ID: %v\n", err) requestId = &uuid.UUID{} } req.Header.Set("X-CF-RequestID", requestId.String()) } rw.Header().Set("X-CF-RequestID", requestId.String()) startEvent := factories.NewHttpStart(req, events.PeerType_Server, requestId) err = ih.emitter.Emit(startEvent) if err != nil { log.Printf("failed to emit start event: %v\n", err) } instrumentedWriter := &instrumentedResponseWriter{writer: rw, statusCode: 200} ih.handler.ServeHTTP(instrumentedWriter, req) stopEvent := factories.NewHttpStop(req, instrumentedWriter.statusCode, instrumentedWriter.contentLength, events.PeerType_Server, requestId) err = ih.emitter.Emit(stopEvent) if err != nil { log.Printf("failed to emit stop event: %v\n", err) } }
/* Wraps the RoundTrip function of the given RoundTripper. Will provide accounting metrics for the http.Request / http.Response life-cycle Callers of RoundTrip are responsible for setting the ‘X-CF-RequestID’ field in the request header if they have one. Callers are also responsible for setting the ‘X-CF-ApplicationID’ and ‘X-CF-InstanceIndex’ fields in the request header if they are known. */ func (irt *instrumentedRoundTripper) RoundTrip(req *http.Request) (*http.Response, error) { requestId, err := GenerateUuid() if err != nil { log.Printf("failed to generated request ID: %v\n", err) requestId = &uuid.UUID{} } httpStart := factories.NewHttpStart(req, events.PeerType_Client, requestId) parentRequestId, err := uuid.ParseHex(req.Header.Get("X-CF-RequestID")) if err == nil { httpStart.ParentRequestId = factories.NewUUID(parentRequestId) } req.Header.Set("X-CF-RequestID", requestId.String()) err = irt.emitter.Emit(httpStart) if err != nil { log.Printf("failed to emit start event: %v\n", err) } resp, roundTripErr := irt.roundTripper.RoundTrip(req) var httpStop *events.HttpStop if roundTripErr != nil { httpStop = factories.NewHttpStop(req, 0, 0, events.PeerType_Client, requestId) } else { httpStop = factories.NewHttpStop(req, resp.StatusCode, resp.ContentLength, events.PeerType_Client, requestId) } err = irt.emitter.Emit(httpStop) if err != nil { log.Printf("failed to emit stop event: %v\n", err) } return resp, roundTripErr }
Describe("NewHttpStop", func() { BeforeEach(func() { req.Header.Set("X-CF-ApplicationID", applicationId.String()) }) It("should set appropriate fields", func() { expectedStopEvent := &events.HttpStop{ ApplicationId: factories.NewUUID(applicationId), RequestId: factories.NewUUID(requestId), Uri: proto.String("foo.example.com/"), PeerType: events.PeerType_Server.Enum(), StatusCode: proto.Int32(200), ContentLength: proto.Int64(3), } stopEvent := factories.NewHttpStop(req, 200, 3, events.PeerType_Server, requestId) Expect(stopEvent.GetTimestamp()).ToNot(BeZero()) stopEvent.Timestamp = nil Expect(stopEvent).To(Equal(expectedStopEvent)) }) }) Describe("StringFromUUID", func() { It("returns a string for a UUID", func() { id := factories.NewUUID(requestId) Expect(factories.StringFromUUID(id)).To(Equal(requestId.String())) }) }) })