/*
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{}
	}

	startTime := time.Now()
	parentRequestId := req.Header.Get("X-CF-RequestID")
	req.Header.Set("X-CF-RequestID", requestId.String())

	resp, roundTripErr := irt.roundTripper.RoundTrip(req)

	var statusCode int
	var contentLength int64
	if roundTripErr == nil {
		statusCode = resp.StatusCode
		contentLength = resp.ContentLength
	}

	httpStartStop := factories.NewHttpStartStop(req, statusCode, contentLength, events.PeerType_Client, requestId)
	if parentRequestId != "" {
		if id, err := uuid.ParseHex(parentRequestId); err == nil {
			httpStartStop.ParentRequestId = factories.NewUUID(id)
		}
	}
	httpStartStop.StartTimestamp = proto.Int64(startTime.UnixNano())

	err = irt.emitter.Emit(httpStartStop)
	if err != nil {
		log.Printf("failed to emit startstop event: %v\n", err)
	}

	return resp, roundTripErr
}
func basicHTTPStopEventEnvelope() *events.Envelope {
	uuid, _ := uuid.ParseHex("9f45fa9d-dbf8-463e-425f-a79d30e1b56f")
	return &events.Envelope{
		Origin:    proto.String("fake-origin-2"),
		EventType: events.Envelope_HttpStop.Enum(),
		HttpStop: &events.HttpStop{
			Timestamp:     proto.Int64(12),
			Uri:           proto.String("some uri"),
			RequestId:     factories.NewUUID(uuid),
			PeerType:      events.PeerType_Client.Enum(),
			StatusCode:    proto.Int32(404),
			ContentLength: proto.Int64(98475189),
		},
	}
}
func basicHTTPStopMessageEnvelope(requestId string) *events.Envelope {
	uuid, _ := uuid.ParseHex(requestId)
	return &events.Envelope{
		Origin:    proto.String("fake-origin-2"),
		EventType: events.Envelope_HttpStop.Enum(),
		HttpStop: &events.HttpStop{
			Timestamp:     proto.Int64(12),
			Uri:           proto.String("some uri"),
			RequestId:     factories.NewUUID(uuid),
			PeerType:      events.PeerType_Client.Enum(),
			StatusCode:    proto.Int32(404),
			ContentLength: proto.Int64(98475189),
		},
	}
}
func basicHTTPStartEventEnvelope() *events.Envelope {
	uuid, _ := uuid.ParseHex("9f45fa9d-dbf8-463e-425f-a79d30e1b56f")
	return &events.Envelope{
		Origin:    proto.String("fake-origin-2"),
		EventType: events.Envelope_HttpStart.Enum(),
		HttpStart: &events.HttpStart{
			Timestamp:     proto.Int64(12),
			RequestId:     factories.NewUUID(uuid),
			PeerType:      events.PeerType_Client.Enum(),
			Method:        events.Method_GET.Enum(),
			Uri:           proto.String("some uri"),
			RemoteAddress: proto.String("some address"),
			UserAgent:     proto.String("some user agent"),
		},
	}
}
/*
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
}
		req.Header.Set("X-Vcap-Request-Id", requestId.String())
		conn.WriteRequest(req)

		findStartStopEvent := func() *events.HttpStartStop {
			for _, event := range fakeEmitter.GetEvents() {
				startStopEvent, ok := event.(*events.HttpStartStop)
				if ok {
					return startStopEvent
				}
			}

			return nil
		}

		Eventually(findStartStopEvent).ShouldNot(BeNil())
		Expect(findStartStopEvent().GetParentRequestId()).To(Equal(factories.NewUUID(requestId)))

		conn.ReadResponse()
	})

	It("X-CF-InstanceID header is added with host:port information if NOT present in the routing endpoint", func() {
		done := make(chan string)

		ln := registerHandler(r, "app", func(conn *test_util.HttpConn) {
			req, err := http.ReadRequest(conn.Reader)
			Expect(err).NotTo(HaveOccurred())

			resp := test_util.NewResponse(http.StatusOK)
			conn.WriteResponse(resp)
			conn.Close()
		var origin string

		BeforeEach(func() {
			origin = "testEventFormatter/42"
		})

		It("works with dropsonde status (Heartbeat) events", func() {
			statusEvent := &events.Heartbeat{SentCount: proto.Uint64(1), ErrorCount: proto.Uint64(0)}
			envelope, _ := emitter.Wrap(statusEvent, origin)
			Expect(envelope.GetEventType()).To(Equal(events.Envelope_Heartbeat))
			Expect(envelope.GetHeartbeat()).To(Equal(statusEvent))
		})

		It("works with HttpStart events", func() {
			id, _ := uuid.NewV4()
			testEvent := &events.HttpStart{RequestId: factories.NewUUID(id)}

			envelope, _ := emitter.Wrap(testEvent, origin)
			Expect(envelope.GetEventType()).To(Equal(events.Envelope_HttpStart))
			Expect(envelope.GetHttpStart()).To(Equal(testEvent))
		})

		It("works with HttpStop events", func() {
			id, _ := uuid.NewV4()
			testEvent := &events.HttpStop{RequestId: factories.NewUUID(id)}

			envelope, _ := emitter.Wrap(testEvent, origin)
			Expect(envelope.GetEventType()).To(Equal(events.Envelope_HttpStop))
			Expect(envelope.GetHttpStop()).To(Equal(testEvent))
		})
Exemple #8
0
		conn.WriteRequest(req)

		findStartStopEvent := func() *events.HttpStartStop {
			for _, event := range fakeEmitter.GetEvents() {
				startStopEvent, ok := event.(*events.HttpStartStop)
				if ok {
					return startStopEvent
				}
			}

			return nil
		}

		Eventually(findStartStopEvent).ShouldNot(BeNil())

		Expect(findStartStopEvent().RequestId).To(Equal(factories.NewUUID(requestId)))
		conn.ReadResponse()
	})

	It("X-CF-InstanceID header is added with host:port information if NOT present in the routing endpoint", func() {
		done := make(chan string)

		ln := registerHandler(r, "app", func(conn *test_util.HttpConn) {
			req, err := http.ReadRequest(conn.Reader)
			Expect(err).NotTo(HaveOccurred())

			resp := test_util.NewResponse(http.StatusOK)
			conn.WriteResponse(resp)
			conn.Close()

			done <- req.Header.Get(router_http.CfInstanceIdHeader)
			Expect(fakeEmitter.Messages[0].Event).To(BeAssignableToTypeOf(new(events.HttpStart)))
			Expect(fakeEmitter.Messages[0].Origin).To(Equal("testRoundtripper/42"))
		})

		Context("if request ID already exists", func() {
			var existingRequestId *uuid.UUID

			BeforeEach(func() {
				existingRequestId, _ = uuid.NewV4()
				req.Header.Set("X-CF-RequestID", existingRequestId.String())
			})

			It("should emit the existing request ID as the parent request ID", func() {
				rt.RoundTrip(req)
				startEvent := fakeEmitter.Messages[0].Event.(*events.HttpStart)
				Expect(startEvent.GetParentRequestId()).To(Equal(factories.NewUUID(existingRequestId)))
			})
		})

		Context("if round tripper returns an error", func() {
			It("should emit a stop event with blank response fields", func() {
				fakeRoundTripper.FakeError = errors.New("fakeEmitter error")
				rt.RoundTrip(req)

				Expect(fakeEmitter.Messages[1].Event).To(BeAssignableToTypeOf(new(events.HttpStop)))

				stopEvent := fakeEmitter.Messages[1].Event.(*events.HttpStop)
				Expect(stopEvent.GetStatusCode()).To(BeNumerically("==", 0))
				Expect(stopEvent.GetContentLength()).To(BeNumerically("==", 0))
			})
		})
	BeforeEach(func() {
		applicationId, _ = uuid.NewV4()
		requestId, _ = uuid.NewV4()
		req, _ = http.NewRequest("GET", "http://foo.example.com/", nil)

		req.RemoteAddr = "127.0.0.1"
		req.Header.Set("User-Agent", "our-testing-client")
	})

	Describe("NewHttpStart", func() {

		Context("without an application ID or instanceIndex", func() {

			It("should set appropriate fields", func() {
				expectedStartEvent := &events.HttpStart{
					RequestId:     factories.NewUUID(requestId),
					PeerType:      events.PeerType_Server.Enum(),
					Method:        events.Method_GET.Enum(),
					Uri:           proto.String("foo.example.com/"),
					RemoteAddress: proto.String("127.0.0.1"),
					UserAgent:     proto.String("our-testing-client"),
				}

				startEvent := factories.NewHttpStart(req, events.PeerType_Server, requestId)

				Expect(startEvent.GetTimestamp()).ToNot(BeZero())
				startEvent.Timestamp = nil

				Expect(startEvent).To(Equal(expectedStartEvent))
			})
		})