func TestHttpMetricUpdate(t *testing.T) { hmr := NewHttpMetricReporter() // add datapoint hm := &HttpMetric{gogrinder.Meta{"01_tc", "01_01_ts", 0, 0, gogrinder.Timestamp(time.Now()), gogrinder.Elapsed(600 * time.Millisecond), "something is wrong!"}, gogrinder.Elapsed(500 * time.Millisecond), 10240, http.StatusOK} hmr.Update(hm) // check that datapoint was reported if exp, got := 600.0, readSummaryVec(hmr.elapsed, prometheus.Labels{"teststep": "01_01_ts"})[0].GetValue(); exp != got { t.Errorf("Expected elapsed %d, got %d.", exp, got) } if exp, got := 500.0, readSummaryVec(hmr.firstByte, prometheus.Labels{"teststep": "01_01_ts"})[0].GetValue(); exp != got { t.Errorf("Expected firstByte %d, got %d.", exp, got) } if exp, got := 10.0, readSummaryVec(hmr.bytes, prometheus.Labels{"teststep": "01_01_ts"})[0].GetValue(); exp != got { t.Errorf("Expected kb %d, got %d.", exp, got) } if exp, got := 1.0, readCounterVec(hmr.error, prometheus.Labels{"teststep": "01_01_ts"}); exp != got { t.Errorf("Expected error counter %f, got %f.", exp, got) } if exp, got := 1.0, readCounterVec(hmr.code, prometheus.Labels{"teststep": "01_01_ts", "code": "200"}); exp != got { t.Errorf("Expected code counter %f, got %f.", exp, got) } }
func (fb *metricReader) Read(p []byte) (n int, err error) { if fb.firstByteAfter == gogrinder.Elapsed(0) { fb.readFrom.ReadByte() fb.firstByteAfter = gogrinder.Elapsed(time.Now().Sub(fb.start)) fb.readFrom.UnreadByte() } n, err = fb.readFrom.Read(p) fb.bytes += n return }
// RAW func DoRaw(c *http.Client, r *http.Request, m *gogrinder.Meta) ([]byte, http.Header, *HttpMetric) { hm := &HttpMetric{*m, gogrinder.Elapsed(0), 0, 421} // http status Misdirected Request resp, err := c.Do(r) if err != nil { hm.Error += err.Error() } if resp != nil { defer resp.Body.Close() mr := newMetricReader(resp.Body) // read the response body raw, err := ioutil.ReadAll(mr) if err != nil { hm.Error += err.Error() } hm.FirstByte = mr.firstByteAfter hm.Bytes = mr.bytes hm.Code = resp.StatusCode return raw, resp.Header, hm } return nil, nil, hm }
func TestFirstByteAfterReader(t *testing.T) { time.Freeze(time.Now()) defer time.Unfreeze() tr := testReader{} fbr := newMetricReader(tr) b1 := make([]byte, 4) fbr.Read(b1) body := string(b1) if !(body == "mark") { t.Fatalf("Read buffer was expected '%s', but was: '%v'", "mark", body) } if fbr.firstByteAfter != gogrinder.Elapsed(55*time.Millisecond) { t.Fatalf("First byte was expected after 55 ms but was: %v", fbr.firstByteAfter) } // read a second time b2 := make([]byte, 4) fbr.Read(b2) body = string(b2) if body != "fink" { t.Fatalf("Read buffer was expected '%s', but was: '%v'", "fink", body) } }
// JSON func DoJson(c *http.Client, r *http.Request, m *gogrinder.Meta) (map[string]interface{}, http.Header, *HttpMetric) { hm := &HttpMetric{*m, gogrinder.Elapsed(0), 0, 421} // http status Misdirected Request resp, err := c.Do(r) if err != nil { hm.Error += err.Error() } if resp != nil { defer resp.Body.Close() mr := newMetricReader(resp.Body) // read the response body and parse as json raw, err := ioutil.ReadAll(mr) if err != nil { m.Error += err.Error() } doc := make(map[string]interface{}) if len(raw) > 0 { if raw[0] == '[' { // a REST service response to be an array does not seem to be a good idea: // http://stackoverflow.com/questions/12293979/how-do-i-return-a-json-array-with-bottle // many applications do this anyway... // so for now we need a workaround: var array []interface{} err = json.Unmarshal(raw, &array) doc["data"] = array } else { err = json.Unmarshal(raw, &doc) } if err != nil { m.Error += err.Error() } } hm.FirstByte = mr.firstByteAfter hm.Bytes = mr.bytes hm.Code = resp.StatusCode return doc, resp.Header, hm } return nil, nil, hm }
// DOC func Do(c *http.Client, r *http.Request, m *gogrinder.Meta) (*goquery.Document, http.Header, *HttpMetric) { hm := &HttpMetric{*m, gogrinder.Elapsed(0), 0, 421} // http status Misdirected Request resp, err := c.Do(r) if err != nil { hm.Error += err.Error() } if resp != nil { defer resp.Body.Close() mr := newMetricReader(resp.Body) // read the response body and parse into document doc, err := goquery.NewDocumentFromReader(mr) if err != nil { m.Error += err.Error() } hm.FirstByte = mr.firstByteAfter hm.Bytes = mr.bytes hm.Code = resp.StatusCode return doc, resp.Header, hm } return nil, nil, hm }
func newMetricReader(readFrom io.Reader) *metricReader { // wrap into buffered reader return &metricReader{0, time.Now(), gogrinder.Elapsed(0), bufio.NewReader(readFrom)} }