Add content_length metric to http_response input plugin (#6261)
This commit is contained in:
parent
beb788bfc6
commit
50dc8d5659
|
@ -61,6 +61,7 @@ This input plugin checks HTTP/HTTPS connections.
|
||||||
- result ([see below](#result--result_code))
|
- result ([see below](#result--result_code))
|
||||||
- fields:
|
- fields:
|
||||||
- response_time (float, seconds)
|
- response_time (float, seconds)
|
||||||
|
- content_length (int, response body length)
|
||||||
- response_string_match (int, 0 = mismatch / body read error, 1 = match)
|
- response_string_match (int, 0 = mismatch / body read error, 1 = match)
|
||||||
- http_response_code (int, response status code)
|
- http_response_code (int, response status code)
|
||||||
- result_type (string, deprecated in 1.6: use `result` tag and `result_code` field)
|
- result_type (string, deprecated in 1.6: use `result` tag and `result_code` field)
|
||||||
|
@ -85,5 +86,5 @@ This tag is used to expose network and plugin errors. HTTP errors are considered
|
||||||
### Example Output:
|
### Example Output:
|
||||||
|
|
||||||
```
|
```
|
||||||
http_response,method=GET,server=http://www.github.com,status_code=200,result=success http_response_code=200i,response_time=6.223266528,result_type="success",result_code=0i 1459419354977857955
|
http_response,method=GET,result=success,server=http://github.com,status_code=200 content_length=87878i,http_response_code=200i,response_time=0.937655534,result_code=0i,result_type="success" 1565839598000000000
|
||||||
```
|
```
|
||||||
|
|
|
@ -272,26 +272,27 @@ func (h *HTTPResponse) httpGather(u string) (map[string]interface{}, map[string]
|
||||||
|
|
||||||
// This function closes the response body, as
|
// This function closes the response body, as
|
||||||
// required by the net/http library
|
// required by the net/http library
|
||||||
defer func() {
|
defer resp.Body.Close()
|
||||||
io.Copy(ioutil.Discard, resp.Body)
|
|
||||||
resp.Body.Close()
|
|
||||||
}()
|
|
||||||
|
|
||||||
// Set log the HTTP response code
|
// Set log the HTTP response code
|
||||||
tags["status_code"] = strconv.Itoa(resp.StatusCode)
|
tags["status_code"] = strconv.Itoa(resp.StatusCode)
|
||||||
fields["http_response_code"] = resp.StatusCode
|
fields["http_response_code"] = resp.StatusCode
|
||||||
|
|
||||||
|
bodyBytes, err := ioutil.ReadAll(resp.Body)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("D! Failed to read body of HTTP Response : %s", err)
|
||||||
|
setResult("body_read_error", fields, tags)
|
||||||
|
fields["content_length"] = len(bodyBytes)
|
||||||
|
if h.ResponseStringMatch != "" {
|
||||||
|
fields["response_string_match"] = 0
|
||||||
|
}
|
||||||
|
return fields, tags, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
fields["content_length"] = len(bodyBytes)
|
||||||
|
|
||||||
// Check the response for a regex match.
|
// Check the response for a regex match.
|
||||||
if h.ResponseStringMatch != "" {
|
if h.ResponseStringMatch != "" {
|
||||||
|
|
||||||
bodyBytes, err := ioutil.ReadAll(resp.Body)
|
|
||||||
if err != nil {
|
|
||||||
log.Printf("D! Failed to read body of HTTP Response : %s", err)
|
|
||||||
setResult("body_read_error", fields, tags)
|
|
||||||
fields["response_string_match"] = 0
|
|
||||||
return fields, tags, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
if h.compiledStringMatch.Match(bodyBytes) {
|
if h.compiledStringMatch.Match(bodyBytes) {
|
||||||
setResult("success", fields, tags)
|
setResult("success", fields, tags)
|
||||||
fields["response_string_match"] = 1
|
fields["response_string_match"] = 1
|
||||||
|
|
|
@ -165,6 +165,7 @@ func TestHeaders(t *testing.T) {
|
||||||
"result_type": "success",
|
"result_type": "success",
|
||||||
"result_code": 0,
|
"result_code": 0,
|
||||||
"response_time": nil,
|
"response_time": nil,
|
||||||
|
"content_length": nil,
|
||||||
}
|
}
|
||||||
expectedTags := map[string]interface{}{
|
expectedTags := map[string]interface{}{
|
||||||
"server": nil,
|
"server": nil,
|
||||||
|
@ -201,6 +202,7 @@ func TestFields(t *testing.T) {
|
||||||
"result_type": "success",
|
"result_type": "success",
|
||||||
"result_code": 0,
|
"result_code": 0,
|
||||||
"response_time": nil,
|
"response_time": nil,
|
||||||
|
"content_length": nil,
|
||||||
}
|
}
|
||||||
expectedTags := map[string]interface{}{
|
expectedTags := map[string]interface{}{
|
||||||
"server": nil,
|
"server": nil,
|
||||||
|
@ -262,6 +264,7 @@ func TestInterface(t *testing.T) {
|
||||||
"result_type": "success",
|
"result_type": "success",
|
||||||
"result_code": 0,
|
"result_code": 0,
|
||||||
"response_time": nil,
|
"response_time": nil,
|
||||||
|
"content_length": nil,
|
||||||
}
|
}
|
||||||
expectedTags := map[string]interface{}{
|
expectedTags := map[string]interface{}{
|
||||||
"server": nil,
|
"server": nil,
|
||||||
|
@ -297,6 +300,7 @@ func TestRedirects(t *testing.T) {
|
||||||
"result_type": "success",
|
"result_type": "success",
|
||||||
"result_code": 0,
|
"result_code": 0,
|
||||||
"response_time": nil,
|
"response_time": nil,
|
||||||
|
"content_length": nil,
|
||||||
}
|
}
|
||||||
expectedTags := map[string]interface{}{
|
expectedTags := map[string]interface{}{
|
||||||
"server": nil,
|
"server": nil,
|
||||||
|
@ -362,6 +366,7 @@ func TestMethod(t *testing.T) {
|
||||||
"result_type": "success",
|
"result_type": "success",
|
||||||
"result_code": 0,
|
"result_code": 0,
|
||||||
"response_time": nil,
|
"response_time": nil,
|
||||||
|
"content_length": nil,
|
||||||
}
|
}
|
||||||
expectedTags := map[string]interface{}{
|
expectedTags := map[string]interface{}{
|
||||||
"server": nil,
|
"server": nil,
|
||||||
|
@ -391,6 +396,7 @@ func TestMethod(t *testing.T) {
|
||||||
"result_type": "success",
|
"result_type": "success",
|
||||||
"result_code": 0,
|
"result_code": 0,
|
||||||
"response_time": nil,
|
"response_time": nil,
|
||||||
|
"content_length": nil,
|
||||||
}
|
}
|
||||||
expectedTags = map[string]interface{}{
|
expectedTags = map[string]interface{}{
|
||||||
"server": nil,
|
"server": nil,
|
||||||
|
@ -421,6 +427,7 @@ func TestMethod(t *testing.T) {
|
||||||
"result_type": "success",
|
"result_type": "success",
|
||||||
"result_code": 0,
|
"result_code": 0,
|
||||||
"response_time": nil,
|
"response_time": nil,
|
||||||
|
"content_length": nil,
|
||||||
}
|
}
|
||||||
expectedTags = map[string]interface{}{
|
expectedTags = map[string]interface{}{
|
||||||
"server": nil,
|
"server": nil,
|
||||||
|
@ -456,6 +463,7 @@ func TestBody(t *testing.T) {
|
||||||
"result_type": "success",
|
"result_type": "success",
|
||||||
"result_code": 0,
|
"result_code": 0,
|
||||||
"response_time": nil,
|
"response_time": nil,
|
||||||
|
"content_length": nil,
|
||||||
}
|
}
|
||||||
expectedTags := map[string]interface{}{
|
expectedTags := map[string]interface{}{
|
||||||
"server": nil,
|
"server": nil,
|
||||||
|
@ -520,6 +528,7 @@ func TestStringMatch(t *testing.T) {
|
||||||
"result_type": "success",
|
"result_type": "success",
|
||||||
"result_code": 0,
|
"result_code": 0,
|
||||||
"response_time": nil,
|
"response_time": nil,
|
||||||
|
"content_length": nil,
|
||||||
}
|
}
|
||||||
expectedTags := map[string]interface{}{
|
expectedTags := map[string]interface{}{
|
||||||
"server": nil,
|
"server": nil,
|
||||||
|
@ -556,6 +565,7 @@ func TestStringMatchJson(t *testing.T) {
|
||||||
"result_type": "success",
|
"result_type": "success",
|
||||||
"result_code": 0,
|
"result_code": 0,
|
||||||
"response_time": nil,
|
"response_time": nil,
|
||||||
|
"content_length": nil,
|
||||||
}
|
}
|
||||||
expectedTags := map[string]interface{}{
|
expectedTags := map[string]interface{}{
|
||||||
"server": nil,
|
"server": nil,
|
||||||
|
@ -593,6 +603,7 @@ func TestStringMatchFail(t *testing.T) {
|
||||||
"result_type": "response_string_mismatch",
|
"result_type": "response_string_mismatch",
|
||||||
"result_code": 1,
|
"result_code": 1,
|
||||||
"response_time": nil,
|
"response_time": nil,
|
||||||
|
"content_length": nil,
|
||||||
}
|
}
|
||||||
expectedTags := map[string]interface{}{
|
expectedTags := map[string]interface{}{
|
||||||
"server": nil,
|
"server": nil,
|
||||||
|
@ -635,7 +646,7 @@ func TestTimeout(t *testing.T) {
|
||||||
"method": "GET",
|
"method": "GET",
|
||||||
"result": "timeout",
|
"result": "timeout",
|
||||||
}
|
}
|
||||||
absentFields := []string{"http_response_code", "response_time", "response_string_match"}
|
absentFields := []string{"http_response_code", "response_time", "content_length", "response_string_match"}
|
||||||
absentTags := []string{"status_code"}
|
absentTags := []string{"status_code"}
|
||||||
checkOutput(t, &acc, expectedFields, expectedTags, absentFields, absentTags)
|
checkOutput(t, &acc, expectedFields, expectedTags, absentFields, absentTags)
|
||||||
}
|
}
|
||||||
|
@ -662,7 +673,7 @@ func TestPluginErrors(t *testing.T) {
|
||||||
err := h.Gather(&acc)
|
err := h.Gather(&acc)
|
||||||
require.Error(t, err)
|
require.Error(t, err)
|
||||||
|
|
||||||
absentFields := []string{"http_response_code", "response_time", "response_string_match", "result_type", "result_code"}
|
absentFields := []string{"http_response_code", "response_time", "content_length", "response_string_match", "result_type", "result_code"}
|
||||||
absentTags := []string{"status_code", "result", "server", "method"}
|
absentTags := []string{"status_code", "result", "server", "method"}
|
||||||
checkOutput(t, &acc, nil, nil, absentFields, absentTags)
|
checkOutput(t, &acc, nil, nil, absentFields, absentTags)
|
||||||
|
|
||||||
|
@ -686,6 +697,7 @@ func TestPluginErrors(t *testing.T) {
|
||||||
"result_type": "body_read_error",
|
"result_type": "body_read_error",
|
||||||
"result_code": 2,
|
"result_code": 2,
|
||||||
"response_time": nil,
|
"response_time": nil,
|
||||||
|
"content_length": nil,
|
||||||
}
|
}
|
||||||
expectedTags := map[string]interface{}{
|
expectedTags := map[string]interface{}{
|
||||||
"server": nil,
|
"server": nil,
|
||||||
|
@ -719,7 +731,7 @@ func TestNetworkErrors(t *testing.T) {
|
||||||
"method": "GET",
|
"method": "GET",
|
||||||
"result": "dns_error",
|
"result": "dns_error",
|
||||||
}
|
}
|
||||||
absentFields := []string{"http_response_code", "response_time", "response_string_match"}
|
absentFields := []string{"http_response_code", "response_time", "content_length", "response_string_match"}
|
||||||
absentTags := []string{"status_code"}
|
absentTags := []string{"status_code"}
|
||||||
checkOutput(t, &acc, expectedFields, expectedTags, absentFields, absentTags)
|
checkOutput(t, &acc, expectedFields, expectedTags, absentFields, absentTags)
|
||||||
|
|
||||||
|
@ -745,7 +757,73 @@ func TestNetworkErrors(t *testing.T) {
|
||||||
"method": "GET",
|
"method": "GET",
|
||||||
"result": "connection_failed",
|
"result": "connection_failed",
|
||||||
}
|
}
|
||||||
absentFields = []string{"http_response_code", "response_time", "response_string_match"}
|
absentFields = []string{"http_response_code", "response_time", "content_length", "response_string_match"}
|
||||||
absentTags = []string{"status_code"}
|
absentTags = []string{"status_code"}
|
||||||
checkOutput(t, &acc, expectedFields, expectedTags, absentFields, absentTags)
|
checkOutput(t, &acc, expectedFields, expectedTags, absentFields, absentTags)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestContentLength(t *testing.T) {
|
||||||
|
mux := setUpTestMux()
|
||||||
|
ts := httptest.NewServer(mux)
|
||||||
|
defer ts.Close()
|
||||||
|
|
||||||
|
h := &HTTPResponse{
|
||||||
|
URLs: []string{ts.URL + "/good"},
|
||||||
|
Body: "{ 'test': 'data'}",
|
||||||
|
Method: "GET",
|
||||||
|
ResponseTimeout: internal.Duration{Duration: time.Second * 20},
|
||||||
|
Headers: map[string]string{
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
},
|
||||||
|
FollowRedirects: true,
|
||||||
|
}
|
||||||
|
var acc testutil.Accumulator
|
||||||
|
err := h.Gather(&acc)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
expectedFields := map[string]interface{}{
|
||||||
|
"http_response_code": http.StatusOK,
|
||||||
|
"result_type": "success",
|
||||||
|
"result_code": 0,
|
||||||
|
"response_time": nil,
|
||||||
|
"content_length": len([]byte("hit the good page!")),
|
||||||
|
}
|
||||||
|
expectedTags := map[string]interface{}{
|
||||||
|
"server": nil,
|
||||||
|
"method": "GET",
|
||||||
|
"status_code": "200",
|
||||||
|
"result": "success",
|
||||||
|
}
|
||||||
|
absentFields := []string{"response_string_match"}
|
||||||
|
checkOutput(t, &acc, expectedFields, expectedTags, absentFields, nil)
|
||||||
|
|
||||||
|
h = &HTTPResponse{
|
||||||
|
URLs: []string{ts.URL + "/musthaveabody"},
|
||||||
|
Body: "{ 'test': 'data'}",
|
||||||
|
Method: "GET",
|
||||||
|
ResponseTimeout: internal.Duration{Duration: time.Second * 20},
|
||||||
|
Headers: map[string]string{
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
},
|
||||||
|
FollowRedirects: true,
|
||||||
|
}
|
||||||
|
acc = testutil.Accumulator{}
|
||||||
|
err = h.Gather(&acc)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
expectedFields = map[string]interface{}{
|
||||||
|
"http_response_code": http.StatusOK,
|
||||||
|
"result_type": "success",
|
||||||
|
"result_code": 0,
|
||||||
|
"response_time": nil,
|
||||||
|
"content_length": len([]byte("sent a body!")),
|
||||||
|
}
|
||||||
|
expectedTags = map[string]interface{}{
|
||||||
|
"server": nil,
|
||||||
|
"method": "GET",
|
||||||
|
"status_code": "200",
|
||||||
|
"result": "success",
|
||||||
|
}
|
||||||
|
absentFields = []string{"response_string_match"}
|
||||||
|
checkOutput(t, &acc, expectedFields, expectedTags, absentFields, nil)
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue