Skip to content
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

Added 'query' parameter to metricbeats global configuration #8292

Merged
1 change: 1 addition & 0 deletions CHANGELOG.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,7 @@ https://github.com/elastic/beats/compare/v6.4.0...master[Check the HEAD diff]
- Allow TCP helper to support delimiters and graphite module to accept multiple metrics in a single payload. {pull}8278[8278]
- Added 'died' PID state to process_system metricset on system module{pull}8275[8275]
- Added `ccr` metricset to Elasticsearch module. {pull}8335[8335]
- Added support for query params in configuration {pull}8286[8286]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, the referenced issue here is the bug report, but the tag is for pull. You can reference any of them here, or both, but use pull for the pull request and issue for the issue. Usually the PR is always referenced and sometimes also the issue.

- Support for Kafka 2.0.0 {pull}8399[8399]

*Packetbeat*
Expand Down
15 changes: 15 additions & 0 deletions metricbeat/docs/metricbeat-options.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -248,3 +248,18 @@ and then use the value in an HTTP Authorization header.

An optional base path to be used in HTTP URIs. If defined, Metricbeat will insert this value
as the first segment in the HTTP URI path.

[float]
==== `query`

An optional value to pass common query params in YAML. Instead of setting the query params within hosts values using the syntax `?key=value&key2&value2`, you can set it here like this:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This line could be wrapped with similar length as the others in the file.


[source,yaml]
----
query:
key: value
key2: value2
list:
- 1.1
- 2.95
- -15
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

---- missing after the code snippet?

35 changes: 33 additions & 2 deletions metricbeat/mb/mb.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,9 @@ to implement Modules and their associated MetricSets.
package mb

import (
"encoding/json"
"fmt"
"net/url"
"time"

"github.com/elastic/beats/libbeat/common"
Expand Down Expand Up @@ -306,17 +308,46 @@ type ModuleConfig struct {
MetricSets []string `config:"metricsets"`
Enabled bool `config:"enabled"`
Raw bool `config:"raw"`
Query QueryParams `config:"query"`
}

func (c ModuleConfig) String() string {
return fmt.Sprintf(`{Module:"%v", MetricSets:%v, Enabled:%v, `+
`Hosts:[%v hosts], Period:"%v", Timeout:"%v", Raw:%v}`,
`Hosts:[%v hosts], Period:"%v", Timeout:"%v", Raw:%v, Query:%v}`,
c.Module, c.MetricSets, c.Enabled, len(c.Hosts), c.Period, c.Timeout,
c.Raw)
c.Raw, c.Query)
}

func (c ModuleConfig) GoString() string { return c.String() }

// QueryParams is a convenient map[string]interface{} wrapper to implement the String interface which returns the
// values in common query params format (key=value&key2=value2) which is the way that the url package expects this
// params (without the initial '?')
type QueryParams map[string]interface{}

// String returns the values in common query params format (key=value&key2=value2) which is the way that the url
// package expects this params (without the initial '?')
func (q QueryParams) String() (s string) {
u := url.Values{}

for k, v := range q {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You could also use url.Values for this

if values, ok := v.([]interface{}); ok {
for _, innerValue := range values {
u.Add(k, fmt.Sprintf("%v", innerValue))
}
} else {
//nil values in YAML shouldn't be stringified anyhow
if v == nil {
u.Add(k, "")
} else {
u.Add(k, fmt.Sprintf("%v", v))
sayden marked this conversation as resolved.
Show resolved Hide resolved
}
}
}

return u.Encode()
}

// defaultModuleConfig contains the default values for ModuleConfig instances.
var defaultModuleConfig = ModuleConfig{
Enabled: true,
Expand Down
25 changes: 24 additions & 1 deletion metricbeat/mb/mb_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -206,7 +206,7 @@ func TestNewModulesHostParser(t *testing.T) {
r := newTestRegistry(t)

factory := func(base BaseMetricSet) (MetricSet, error) {
return &testMetricSet{base}, nil
return &testMetricSet{BaseMetricSet: base}, nil
}

hostParser := func(m Module, rawHost string) (HostData, error) {
Expand Down Expand Up @@ -375,3 +375,26 @@ func newConfig(t testing.TB, moduleConfig interface{}) *common.Config {
}
return config
}

func TestModuleConfigQueryParams(t *testing.T) {
qp := QueryParams{
"stringKey": "value",
"intKey": 10,
"floatKey": 11.5,
"boolKey": true,
"nullKey": nil,
"arKey": []interface{}{1, 2},
}

res := qp.String()

expectedValues := []string{"stringKey=value", "intKey=10", "floatKey=11.5", "boolKey=true", "nullKey=", "arKey=1", "arKey=2"}
for _, expected := range expectedValues {
assert.Contains(t, res, expected)
}

assert.NotContains(t, res, "?")
assert.NotContains(t, res, "%")
assert.NotEqual(t, "&", res[0])
assert.NotEqual(t, "&", res[len(res)-1])
}
10 changes: 10 additions & 0 deletions metricbeat/mb/parse/url.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,16 @@ func (b URLHostParserBuilder) Build() mb.HostParser {
return mb.HostData{}, err
}

query, ok := conf["query"]
if ok {
queryMap, ok := query.(map[string]interface{})
if !ok {
return mb.HostData{}, errors.Errorf("'query' config for module %v is not a map", module.Name())
}

b.QueryParams = mb.QueryParams(queryMap).String()
}

var user, pass, path, basePath string
t, ok := conf["username"]
if ok {
Expand Down
3 changes: 3 additions & 0 deletions metricbeat/mb/parse/url_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ package parse
import (
"testing"

"github.com/elastic/beats/metricbeat/mb"

mbtest "github.com/elastic/beats/metricbeat/mb/testing"

"github.com/stretchr/testify/assert"
Expand Down Expand Up @@ -118,6 +120,7 @@ func TestURLHostParserBuilder(t *testing.T) {
{map[string]interface{}{"basepath": "foo/"}, URLHostParserBuilder{DefaultPath: "/default"}, "http://example.com/foo/default"},
{map[string]interface{}{"basepath": "/foo/"}, URLHostParserBuilder{DefaultPath: "/default"}, "http://example.com/foo/default"},
{map[string]interface{}{"basepath": "foo"}, URLHostParserBuilder{DefaultPath: "/default"}, "http://example.com/foo/default"},
{map[string]interface{}{"basepath": "foo"}, URLHostParserBuilder{DefaultPath: "/queryParams", QueryParams: mb.QueryParams{"key": "value"}.String()}, "http://example.com/foo/queryParams?key=value"},
sayden marked this conversation as resolved.
Show resolved Hide resolved
}

for _, test := range cases {
Expand Down