-
Notifications
You must be signed in to change notification settings - Fork 4.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Httpmetricbeat #4092
Httpmetricbeat #4092
Changes from 6 commits
e97377d
4f061e2
e750f90
1977b33
2242883
c442602
621f763
282d81d
3efb9db
856e151
38e04b4
fafe088
4aed040
2bc0a20
de11679
af60958
5afda3d
354fdd6
ca2e449
aaee997
dce6887
a279b5d
7a8bc70
7d15bf3
074add2
bee77ee
24aed8c
1344e4f
b9f1b50
6b01fa9
b845687
ea763e2
946bfd8
92ee85e
81da4f6
2c84adf
521c11c
9d69fd6
47a046c
a3bbadb
494b428
1fca1b0
8eb085f
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
//// | ||
This file is generated! See scripts/docs_collector.py | ||
//// | ||
|
||
[[metricbeat-module-http]] | ||
== http Module | ||
|
||
This is the http Module. | ||
|
||
|
||
|
||
[float] | ||
=== Example Configuration | ||
|
||
The http module supports the standard configuration options that are described | ||
in <<configuration-metricbeat>>. Here is an example configuration: | ||
|
||
[source,yaml] | ||
---- | ||
metricbeat.modules: | ||
- module: http | ||
metricsets: ["json"] | ||
enabled: true | ||
period: 10s | ||
hosts: ["localhost"] | ||
|
||
---- | ||
|
||
[float] | ||
=== Metricsets | ||
|
||
The following metricsets are available: | ||
|
||
* <<metricbeat-metricset-http-json,json>> | ||
|
||
include::http/json.asciidoc[] | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
//// | ||
This file is generated! See scripts/docs_collector.py | ||
//// | ||
|
||
[[metricbeat-metricset-http-json]] | ||
include::../../../module/http/json/_meta/docs.asciidoc[] | ||
|
||
|
||
==== Fields | ||
|
||
For a description of each field in the metricset, see the | ||
<<exported-fields-http,exported fields>> section. | ||
|
||
Here is an example document generated by this metricset: | ||
|
||
[source,json] | ||
---- | ||
include::../../../module/http/json/_meta/data.json[] | ||
---- |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
- module: http | ||
metricsets: ["json"] | ||
enabled: true | ||
period: 10s | ||
hosts: ["localhost"] | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
== http Module | ||
|
||
This is the http Module. | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
- key: http | ||
title: "http" | ||
description: > | ||
http Module | ||
fields: | ||
- name: http | ||
type: group | ||
description: > | ||
fields: |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
/* | ||
Package http is a Metricbeat module that contains MetricSets. | ||
*/ | ||
package http |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
{ | ||
"@timestamp":"2016-05-23T08:05:34.853Z", | ||
"beat":{ | ||
"hostname":"beathost", | ||
"name":"beathost" | ||
}, | ||
"metricset":{ | ||
"host":"localhost", | ||
"module":"http", | ||
"name":"json", | ||
"rtt":44269 | ||
}, | ||
"http":{ | ||
"json":{ | ||
"example": "json" | ||
} | ||
}, | ||
"type":"metricsets" | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
=== http json MetricSet | ||
|
||
This is the json metricset of the module http. |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
- name: json | ||
type: group | ||
description: > | ||
json metricset | ||
fields: | ||
- name: request | ||
type: group | ||
description: > | ||
HTTP request information | ||
fields: | ||
- name: header | ||
type: nested | ||
description: > | ||
The HTTP headers sent | ||
- name: method | ||
type: keyword | ||
description: > | ||
The HTTP method used | ||
- name: body | ||
type: keyword | ||
description: > | ||
The HTTP payload sent | ||
- name: response | ||
type: group | ||
description: > | ||
HTTP response information | ||
fields: | ||
- name: header | ||
type: nested | ||
description: > | ||
The HTTP headers received | ||
- name: status_code | ||
type: keyword | ||
description: > | ||
The HTTP status code | ||
- name: body | ||
type: keyword | ||
description: > | ||
The HTTP payload received |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,108 @@ | ||
package json | ||
|
||
import ( | ||
"github.com/elastic/beats/libbeat/common" | ||
"github.com/elastic/beats/metricbeat/helper" | ||
"github.com/elastic/beats/metricbeat/mb" | ||
"io/ioutil" | ||
"net/http" | ||
"strings" | ||
) | ||
|
||
// init registers the MetricSet with the central registry. | ||
// The New method will be called after the setup of the module and before starting to fetch data | ||
func init() { | ||
if err := mb.Registry.AddMetricSet("http", "json", New); err != nil { | ||
panic(err) | ||
} | ||
} | ||
|
||
// MetricSet type defines all fields of the MetricSet | ||
// As a minimum it must inherit the mb.BaseMetricSet fields, but can be extended with | ||
// additional entries. These variables can be used to persist data or configuration between | ||
// multiple fetch calls. | ||
type MetricSet struct { | ||
mb.BaseMetricSet | ||
http *helper.HTTP | ||
headers map[string]string | ||
method string | ||
body string | ||
} | ||
|
||
// New create a new instance of the MetricSet | ||
// Part of new is also setting up the configuration by processing additional | ||
// configuration entries if needed. | ||
func New(base mb.BaseMetricSet) (mb.MetricSet, error) { | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Could you add here a log message like There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes will do. |
||
config := struct { | ||
Method string `config:"method"` | ||
Body string `config:"body"` | ||
Headers map[string]string `config:"headers"` | ||
}{} | ||
|
||
if err := base.Module().UnpackConfig(&config); err != nil { | ||
return nil, err | ||
} | ||
|
||
http := helper.NewHTTP(base) | ||
http.SetMethod(config.Method) | ||
http.SetBody([]byte(config.Body)) | ||
for key, value := range config.Headers { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. headers are unpacked and added to the http request here: There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. True, saw that as well, but then forgot to change before committing. |
||
http.SetHeader(key, value) | ||
} | ||
|
||
return &MetricSet{ | ||
BaseMetricSet: base, | ||
http: http, | ||
headers: config.Headers, | ||
method: config.Method, | ||
body: config.Body, | ||
}, nil | ||
} | ||
|
||
// Fetch methods implements the data gathering and data conversion to the right format | ||
// It returns the event which is then forward to the output. In case of an error, a | ||
// descriptive error must be returned. | ||
func (m *MetricSet) Fetch() (common.MapStr, error) { | ||
|
||
response, err := m.http.FetchResponse() | ||
if err != nil { | ||
return nil, err | ||
} | ||
defer response.Body.Close() | ||
|
||
responseBody, err := ioutil.ReadAll(response.Body) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
event := common.MapStr{} | ||
|
||
event["request"] = common.MapStr{ | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. As these are based on the configs set, not sure if we should really add the request to each document. What would be the use case here? |
||
"headers": m.headers, | ||
"method": m.method, | ||
"body": m.body, | ||
} | ||
|
||
event["response"] = common.MapStr{ | ||
"status_code": response.StatusCode, | ||
"headers": m.getHeaders(response.Header), | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. As status_code and response header will be the same for all That would mean these are always under I'm not sure if we should enable the headers by default because in the case of json I assume in most use cases people are not too interested in the headers (happy to be convinced otherwise). So I would make it configurable with a config option. As we already have There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There is definitely room for improvement to move some of the information to the module layer. Idea was to get something working and getting familiar with Metricbeat implementation. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Happy to merge the PR rater soonish and do improvements on top of it. For the headers, I probably miss the use case. |
||
"body": responseBody, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. As this is JSON, don't we need to decode it here? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes definitely. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. One more note on the body: I would probably put the decode json directly on the top level and not into a body namespace. |
||
} | ||
|
||
return event, nil | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. True, thanks for the hint. Is namespace here the correct concept, or is it to use different document_types? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Namespace is the one to use here. We don't use document type, especially as it will be removed in 6.0 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ok, will make the changes accordingly. |
||
} | ||
|
||
func (m *MetricSet) getHeaders(header http.Header) map[string]string { | ||
|
||
headers := make(map[string]string) | ||
for k, v := range header { | ||
value := "" | ||
for _, h := range v { | ||
value += h + " ," | ||
} | ||
value = strings.TrimRight(value, " ,") | ||
headers[k] = value | ||
} | ||
return headers | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In case we do not add these fields (see comment below) to the event, they are probably not needed in the object.