[WIP] Add response time to httpjson

This commit is contained in:
Thibault Cohen 2016-01-01 18:16:51 -05:00
parent 069cb9766b
commit 875c8c2290
3 changed files with 116 additions and 95 deletions

View File

@ -51,7 +51,7 @@ func (f *JSONFlattener) FlattenJSON(
}
case float64:
f.Fields[fieldname] = t
case bool, string, []interface{}:
case nil, bool, string, []interface{}:
// ignored types
return nil
default:

View File

@ -9,6 +9,7 @@ import (
"net/url"
"strings"
"sync"
"time"
"github.com/influxdb/telegraf/internal"
"github.com/influxdb/telegraf/plugins"
@ -119,7 +120,8 @@ func (h *HttpJson) gatherServer(
acc plugins.Accumulator,
serverURL string,
) error {
resp, err := h.sendRequest(serverURL)
resp, responseTime, err := h.sendRequest(serverURL)
if err != nil {
return err
}
@ -141,6 +143,9 @@ func (h *HttpJson) gatherServer(
delete(jsonOut, tag)
}
if responseTime >= 0 {
jsonOut["response_time"] = responseTime
}
f := internal.JSONFlattener{}
err = f.FlattenJSON("", jsonOut)
if err != nil {
@ -153,7 +158,7 @@ func (h *HttpJson) gatherServer(
} else {
msrmnt_name = "httpjson_" + h.Name
}
acc.AddFields(msrmnt_name, f.Fields, nil)
acc.AddFields(msrmnt_name, f.Fields, tags)
return nil
}
@ -164,11 +169,11 @@ func (h *HttpJson) gatherServer(
// Returns:
// string: body of the response
// error : Any error that may have occurred
func (h *HttpJson) sendRequest(serverURL string) (string, error) {
func (h *HttpJson) sendRequest(serverURL string) (string, float64, error) {
// Prepare URL
requestURL, err := url.Parse(serverURL)
if err != nil {
return "", fmt.Errorf("Invalid server URL \"%s\"", serverURL)
return "", -1, fmt.Errorf("Invalid server URL \"%s\"", serverURL)
}
params := url.Values{}
@ -180,19 +185,21 @@ func (h *HttpJson) sendRequest(serverURL string) (string, error) {
// Create + send request
req, err := http.NewRequest(h.Method, requestURL.String(), nil)
if err != nil {
return "", err
return "", -1, err
}
start := time.Now()
resp, err := h.client.MakeRequest(req)
if err != nil {
return "", err
return "", -1, err
}
defer resp.Body.Close()
defer resp.Body.Close()
responseTime := time.Since(start).Seconds()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
return string(body), err
return string(body), responseTime, err
}
// Process response
@ -203,10 +210,10 @@ func (h *HttpJson) sendRequest(serverURL string) (string, error) {
http.StatusText(resp.StatusCode),
http.StatusOK,
http.StatusText(http.StatusOK))
return string(body), err
return string(body), responseTime, err
}
return string(body), err
return string(body), responseTime, err
}
func init() {

View File

@ -15,7 +15,7 @@ import (
const validJSON = `
{
"parent": {
"child": 3,
"child": 3.0,
"ignored_child": "hi"
},
"ignored_null": null,
@ -76,65 +76,64 @@ func (c mockHTTPClient) MakeRequest(req *http.Request) (*http.Response, error) {
//
// Returns:
// *HttpJson: Pointer to an HttpJson object that uses the generated mock HTTP client
func genMockHttpJson(response string, statusCode int) *HttpJson {
return &HttpJson{
func genMockHttpJsons(response string, statusCode int) []*HttpJson {
httpjson1 := &HttpJson{
client: mockHTTPClient{responseBody: response, statusCode: statusCode},
Services: []Service{
Service{
Servers: []string{
"http://server1.example.com/metrics/",
"http://server2.example.com/metrics/",
},
Name: "my_webapp",
Method: "GET",
Parameters: map[string]string{
"httpParam1": "12",
"httpParam2": "the second parameter",
},
},
Service{
Servers: []string{
"http://server3.example.com/metrics/",
"http://server4.example.com/metrics/",
},
Name: "other_webapp",
Method: "POST",
Parameters: map[string]string{
"httpParam1": "12",
"httpParam2": "the second parameter",
},
TagKeys: []string{
"role",
"build",
},
},
Servers: []string{
"http://server1.example.com/metrics/",
"http://server2.example.com/metrics/",
},
Name: "my_webapp",
Method: "GET",
Parameters: map[string]string{
"httpParam1": "12",
"httpParam2": "the second parameter",
},
}
httpjson2 := &HttpJson{
client: mockHTTPClient{responseBody: response, statusCode: statusCode},
Servers: []string{
"http://server3.example.com/metrics/",
"http://server4.example.com/metrics/",
},
Name: "other_webapp",
Method: "POST",
Parameters: map[string]string{
"httpParam1": "12",
"httpParam2": "the second parameter",
},
TagKeys: []string{
"role",
"build",
},
}
httpjsons := []*HttpJson{httpjson1, httpjson2}
return httpjsons
}
// Test that the proper values are ignored or collected
func TestHttpJson200(t *testing.T) {
httpjson := genMockHttpJson(validJSON, 200)
httpjsons := genMockHttpJsons(validJSON, 200)
for _, httpjson := range httpjsons {
var acc testutil.Accumulator
err := httpjson.Gather(&acc)
require.NoError(t, err)
var acc testutil.Accumulator
err := httpjson.Gather(&acc)
require.NoError(t, err)
assert.Equal(t, 2, len(acc.Points))
assert.Equal(t, 8, len(acc.Points))
for _, service := range httpjson.Services {
for _, srv := range service.Servers {
for _, srv := range httpjson.Servers {
// Override response time
for _, p := range acc.Points {
p.Fields["response_time"] = 1.0
}
require.NoError(t,
acc.ValidateTaggedValue(
fmt.Sprintf("%s_parent_child", service.Name),
3.0,
map[string]string{"server": srv},
),
)
require.NoError(t,
acc.ValidateTaggedValue(
fmt.Sprintf("%s_integer", service.Name),
4.0,
acc.ValidateTaggedFieldsValue(
fmt.Sprintf("httpjson_%s", httpjson.Name),
map[string]interface{}{
"parent_child": 3.0,
"integer": 4.0,
"response_time": 1.0,
},
map[string]string{"server": srv},
),
)
@ -144,80 +143,95 @@ func TestHttpJson200(t *testing.T) {
// Test response to HTTP 500
func TestHttpJson500(t *testing.T) {
httpjson := genMockHttpJson(validJSON, 500)
httpjsons := genMockHttpJsons(validJSON, 500)
var acc testutil.Accumulator
err := httpjson.Gather(&acc)
for _, httpjson := range httpjsons {
err := httpjson.Gather(&acc)
assert.NotNil(t, err)
// 4 error lines for (2 urls) * (2 services)
assert.Equal(t, len(strings.Split(err.Error(), "\n")), 4)
assert.NotNil(t, err)
// 4 error lines for (2 urls) * (2 services)
assert.Equal(t, len(strings.Split(err.Error(), "\n")), 2)
}
assert.Equal(t, 0, len(acc.Points))
}
// Test response to HTTP 405
func TestHttpJsonBadMethod(t *testing.T) {
httpjson := genMockHttpJson(validJSON, 200)
httpjson.Services[0].Method = "NOT_A_REAL_METHOD"
httpjsons := genMockHttpJsons(validJSON, 200)
var acc testutil.Accumulator
err := httpjson.Gather(&acc)
assert.NotNil(t, err)
// 2 error lines for (2 urls) * (1 falied service)
assert.Equal(t, len(strings.Split(err.Error(), "\n")), 2)
for _, httpjson := range httpjsons {
httpjson.Method = "NOT_A_REAL_METHOD"
err := httpjson.Gather(&acc)
assert.NotNil(t, err)
// 2 error lines for (2 urls) * (1 falied service)
assert.Equal(t, len(strings.Split(err.Error(), "\n")), 2)
}
// (2 measurements) * (2 servers) * (1 successful service)
assert.Equal(t, 4, len(acc.Points))
assert.Equal(t, 0, len(acc.Points))
}
// Test response to malformed JSON
func TestHttpJsonBadJson(t *testing.T) {
httpjson := genMockHttpJson(invalidJSON, 200)
httpjsons := genMockHttpJsons(invalidJSON, 200)
var acc testutil.Accumulator
err := httpjson.Gather(&acc)
for _, httpjson := range httpjsons {
err := httpjson.Gather(&acc)
assert.NotNil(t, err)
// 4 error lines for (2 urls) * (2 services)
assert.Equal(t, len(strings.Split(err.Error(), "\n")), 4)
assert.NotNil(t, err)
// 4 error lines for (2 urls) * (2 services)
assert.Equal(t, len(strings.Split(err.Error(), "\n")), 2)
}
assert.Equal(t, 0, len(acc.Points))
}
// Test response to empty string as response objectgT
func TestHttpJsonEmptyResponse(t *testing.T) {
httpjson := genMockHttpJson(empty, 200)
httpjsons := genMockHttpJsons(empty, 200)
var acc testutil.Accumulator
err := httpjson.Gather(&acc)
for _, httpjson := range httpjsons {
err := httpjson.Gather(&acc)
assert.NotNil(t, err)
// 4 error lines for (2 urls) * (2 services)
assert.Equal(t, len(strings.Split(err.Error(), "\n")), 4)
assert.NotNil(t, err)
// 4 error lines for (2 urls) * (2 services)
assert.Equal(t, len(strings.Split(err.Error(), "\n")), 2)
}
assert.Equal(t, 0, len(acc.Points))
}
// Test that the proper values are ignored or collected
func TestHttpJson200Tags(t *testing.T) {
httpjson := genMockHttpJson(validJSONTags, 200)
httpjsons := genMockHttpJsons(validJSONTags, 200)
var acc testutil.Accumulator
err := httpjson.Gather(&acc)
require.NoError(t, err)
for _, httpjson := range httpjsons {
err := httpjson.Gather(&acc)
require.NoError(t, err)
assert.Equal(t, 4, len(acc.Points))
for _, service := range httpjson.Services {
if service.Name == "other_webapp" {
for _, srv := range service.Servers {
if httpjson.Name == "other_webapp" {
assert.Equal(t, 4, len(acc.Points))
for _, srv := range httpjson.Servers {
// Override response time
for _, p := range acc.Points {
p.Fields["response_time"] = 1.0
}
require.NoError(t,
acc.ValidateTaggedValue(
fmt.Sprintf("%s_value", service.Name),
15.0,
acc.ValidateTaggedFieldsValue(
fmt.Sprintf("httpjson_%s", httpjson.Name),
map[string]interface{}{
"value": 15.0,
"response_time": 1.0,
},
map[string]string{"server": srv, "role": "master", "build": "123"},
),
)
}
} else {
assert.Equal(t, 2, len(acc.Points))
}
}
}