[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: case float64:
f.Fields[fieldname] = t f.Fields[fieldname] = t
case bool, string, []interface{}: case nil, bool, string, []interface{}:
// ignored types // ignored types
return nil return nil
default: default:

View File

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

View File

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