[WIP] Add response time to httpjson
This commit is contained in:
parent
069cb9766b
commit
875c8c2290
|
@ -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:
|
||||||
|
|
|
@ -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() {
|
||||||
|
|
|
@ -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))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue