diff --git a/metricbeat/docs/fields.asciidoc b/metricbeat/docs/fields.asciidoc index c62d528e6240..df7432c9d3fa 100644 --- a/metricbeat/docs/fields.asciidoc +++ b/metricbeat/docs/fields.asciidoc @@ -26258,6 +26258,53 @@ ZooKeeper metrics collected by the four-letter monitoring commands. +[float] +== connection fields + +connections + + + +*`zookeeper.connection.interest_ops`*:: ++ +-- +type: long + +Interest ops + + +-- + +*`zookeeper.connection.queued`*:: ++ +-- +type: long + +Queued connections + + +-- + +*`zookeeper.connection.received`*:: ++ +-- +type: long + +Received connections + + +-- + +*`zookeeper.connection.sent`*:: ++ +-- +type: long + +Connections sent + + +-- + [float] == mntr fields diff --git a/metricbeat/docs/modules/zookeeper.asciidoc b/metricbeat/docs/modules/zookeeper.asciidoc index dce89ec92acb..e101755a5c8a 100644 --- a/metricbeat/docs/modules/zookeeper.asciidoc +++ b/metricbeat/docs/modules/zookeeper.asciidoc @@ -43,10 +43,14 @@ metricbeat.modules: The following metricsets are available: +* <> + * <> * <> +include::zookeeper/connection.asciidoc[] + include::zookeeper/mntr.asciidoc[] include::zookeeper/server.asciidoc[] diff --git a/metricbeat/docs/modules/zookeeper/connection.asciidoc b/metricbeat/docs/modules/zookeeper/connection.asciidoc new file mode 100644 index 000000000000..867a34a0d603 --- /dev/null +++ b/metricbeat/docs/modules/zookeeper/connection.asciidoc @@ -0,0 +1,23 @@ +//// +This file is generated! See scripts/docs_collector.py +//// + +[[metricbeat-metricset-zookeeper-connection]] +=== ZooKeeper connection metricset + +beta[] + +include::../../../module/zookeeper/connection/_meta/docs.asciidoc[] + + +==== Fields + +For a description of each field in the metricset, see the +<> section. + +Here is an example document generated by this metricset: + +[source,json] +---- +include::../../../module/zookeeper/connection/_meta/data.json[] +---- diff --git a/metricbeat/docs/modules_list.asciidoc b/metricbeat/docs/modules_list.asciidoc index 111087981827..93f9f1f55105 100644 --- a/metricbeat/docs/modules_list.asciidoc +++ b/metricbeat/docs/modules_list.asciidoc @@ -166,7 +166,8 @@ This file is generated! See scripts/docs_collector.py .2+| .2+| |<> beta[] |<> |<> |image:./images/icon-yes.png[Prebuilt dashboards are available] | -.2+| .2+| |<> +.3+| .3+| |<> beta[] +|<> |<> |================================ diff --git a/metricbeat/include/list.go b/metricbeat/include/list.go index eee014afda39..5da3b1729200 100644 --- a/metricbeat/include/list.go +++ b/metricbeat/include/list.go @@ -180,6 +180,7 @@ import ( _ "github.com/elastic/beats/metricbeat/module/windows/perfmon" _ "github.com/elastic/beats/metricbeat/module/windows/service" _ "github.com/elastic/beats/metricbeat/module/zookeeper" + _ "github.com/elastic/beats/metricbeat/module/zookeeper/connection" _ "github.com/elastic/beats/metricbeat/module/zookeeper/mntr" _ "github.com/elastic/beats/metricbeat/module/zookeeper/server" ) diff --git a/metricbeat/module/zookeeper/connection/_meta/data.json b/metricbeat/module/zookeeper/connection/_meta/data.json new file mode 100644 index 000000000000..a6c97436283d --- /dev/null +++ b/metricbeat/module/zookeeper/connection/_meta/data.json @@ -0,0 +1,27 @@ +{ + "@timestamp": "2017-10-12T08:05:34.853Z", + "client": { + "ip": "172.17.0.1", + "port": 47728 + }, + "event": { + "dataset": "zookeeper.connection", + "duration": 115000, + "module": "zookeeper" + }, + "metricset": { + "name": "connection" + }, + "service": { + "address": "localhost:2181", + "type": "zookeeper" + }, + "zookeeper": { + "connection": { + "interest_ops": 0, + "queued": 0, + "received": 1, + "sent": 0 + } + } +} \ No newline at end of file diff --git a/metricbeat/module/zookeeper/connection/_meta/docs.asciidoc b/metricbeat/module/zookeeper/connection/_meta/docs.asciidoc new file mode 100644 index 000000000000..1203c43d04fa --- /dev/null +++ b/metricbeat/module/zookeeper/connection/_meta/docs.asciidoc @@ -0,0 +1 @@ +This is the 'connection' metricset of the module zookeeper. diff --git a/metricbeat/module/zookeeper/connection/_meta/fields.yml b/metricbeat/module/zookeeper/connection/_meta/fields.yml new file mode 100644 index 000000000000..1a1c0e552bbb --- /dev/null +++ b/metricbeat/module/zookeeper/connection/_meta/fields.yml @@ -0,0 +1,22 @@ +- name: connection + type: group + release: beta + description: > + connections + fields: + - name: interest_ops + type: long + description: > + Interest ops + - name: queued + type: long + description: > + Queued connections + - name: received + type: long + description: > + Received connections + - name: sent + type: long + description: > + Connections sent diff --git a/metricbeat/module/zookeeper/connection/connection.go b/metricbeat/module/zookeeper/connection/connection.go new file mode 100644 index 000000000000..31540d00b880 --- /dev/null +++ b/metricbeat/module/zookeeper/connection/connection.go @@ -0,0 +1,80 @@ +// Licensed to Elasticsearch B.V. under one or more contributor +// license agreements. See the NOTICE file distributed with +// this work for additional information regarding copyright +// ownership. Elasticsearch B.V. licenses this file to you under +// the Apache License, Version 2.0 (the "License"); you may +// not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package connection + +import ( + "github.com/pkg/errors" + + "github.com/elastic/beats/libbeat/common/cfgwarn" + "github.com/elastic/beats/metricbeat/mb" + "github.com/elastic/beats/metricbeat/mb/parse" + "github.com/elastic/beats/metricbeat/module/zookeeper" +) + +// init registers the MetricSet with the central registry as soon as the program +// starts. The New function will be called later to instantiate an instance of +// the MetricSet for each host defined in the module's configuration. After the +// MetricSet has been created then Fetch will begin to be called periodically. +func init() { + mb.Registry.MustAddMetricSet("zookeeper", "connection", New, + mb.WithHostParser(parse.PassThruHostParser), + ) +} + +// MetricSet holds any configuration or state information. It must implement +// the mb.MetricSet interface. And this is best achieved by embedding +// mb.BaseMetricSet because it implements all of the required mb.MetricSet +// interface methods except for Fetch. +type MetricSet struct { + mb.BaseMetricSet +} + +// New creates a new instance of the MetricSet. New is responsible for unpacking +// any MetricSet specific configuration options if there are any. +func New(base mb.BaseMetricSet) (mb.MetricSet, error) { + cfgwarn.Beta("The zookeeper connection metricset is beta.") + + config := struct{}{} + if err := base.Module().UnpackConfig(&config); err != nil { + return nil, err + } + + return &MetricSet{ + BaseMetricSet: base, + }, nil +} + +// Fetch fetches metrics from ZooKeeper by making a tcp connection to the +// command port and sending the "cons" command and parsing the output. +func (m *MetricSet) Fetch(reporter mb.ReporterV2) error { + outputReader, err := zookeeper.RunCommand("cons", m.Host(), m.Module().Config().Timeout) + if err != nil { + return errors.Wrap(err, "'cons' command failed") + } + + events, err := m.parseCons(outputReader) + if err != nil { + return errors.Wrap(err, "error parsing response from zookeeper") + } + + for _, event := range events { + reporter.Event(event) + } + + return nil +} diff --git a/metricbeat/module/zookeeper/connection/connection_integration_test.go b/metricbeat/module/zookeeper/connection/connection_integration_test.go new file mode 100644 index 000000000000..7437f87842ff --- /dev/null +++ b/metricbeat/module/zookeeper/connection/connection_integration_test.go @@ -0,0 +1,43 @@ +// Licensed to Elasticsearch B.V. under one or more contributor +// license agreements. See the NOTICE file distributed with +// this work for additional information regarding copyright +// ownership. Elasticsearch B.V. licenses this file to you under +// the Apache License, Version 2.0 (the "License"); you may +// not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +// +build integration + +package connection + +import ( + "testing" + + "github.com/elastic/beats/metricbeat/module/zookeeper" + + mbtest "github.com/elastic/beats/metricbeat/mb/testing" +) + +func TestData(t *testing.T) { + f := mbtest.NewReportingMetricSetV2Error(t, getConfig()) + if err := mbtest.WriteEventsReporterV2Error(f, t, ""); err != nil { + t.Fatal("write", err) + } +} + +func getConfig() map[string]interface{} { + return map[string]interface{}{ + "module": "zookeeper", + "metricsets": []string{"connection"}, + "hosts": []string{zookeeper.GetZookeeperEnvHost() + ":" + zookeeper.GetZookeeperEnvPort()}, + } +} diff --git a/metricbeat/module/zookeeper/connection/connection_test.go b/metricbeat/module/zookeeper/connection/connection_test.go new file mode 100644 index 000000000000..253153d3422e --- /dev/null +++ b/metricbeat/module/zookeeper/connection/connection_test.go @@ -0,0 +1,82 @@ +// Licensed to Elasticsearch B.V. under one or more contributor +// license agreements. See the NOTICE file distributed with +// this work for additional information regarding copyright +// ownership. Elasticsearch B.V. licenses this file to you under +// the Apache License, Version 2.0 (the "License"); you may +// not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package connection + +import ( + "bytes" + "testing" + + "github.com/elastic/beats/libbeat/common" + + "github.com/stretchr/testify/assert" +) + +var srvrTestInput = `/172.17.0.1:55218[0](queued=0,recved=1,sent=0) +/172.17.0.2:55218[55](queued=11,recved=22,sent=333) +/2001:0db8:85a3:0000:0000:8a2e:0370:7334:55218[0](queued=11,recved=22,sent=333) +` + +func TestParser(t *testing.T) { + conns := MetricSet{} + + mapStr, err := conns.parseCons(bytes.NewReader([]byte(srvrTestInput))) + if err != nil { + t.Fatal(err) + } + assert.True(t, len(mapStr) == 3) + firstLine := mapStr[0] + secondLine := mapStr[1] + thirdLine := mapStr[2] + + firstLineClient, ok := firstLine.RootFields["client"] + assert.True(t, ok) + + firstLineClientMap, ok := firstLineClient.(common.MapStr) + assert.True(t, ok) + + secondLineClient, ok := secondLine.RootFields["client"] + assert.True(t, ok) + + secondLineClientMap, ok := secondLineClient.(common.MapStr) + assert.True(t, ok) + + thirdLineClient, ok := thirdLine.RootFields["client"] + assert.True(t, ok) + + thirdLineClientMap, ok := thirdLineClient.(common.MapStr) + assert.True(t, ok) + + assert.Equal(t, "172.17.0.1", firstLineClientMap["ip"]) + assert.Equal(t, "172.17.0.2", secondLineClientMap["ip"]) + assert.Equal(t, "2001:0db8:85a3:0000:0000:8a2e:0370:7334", thirdLineClientMap["ip"]) + + assert.Equal(t, int64(55218), firstLineClientMap["port"]) + assert.Equal(t, int64(55218), secondLineClientMap["port"]) + + assert.Equal(t, int64(0), firstLine.MetricSetFields["interest_ops"]) + assert.Equal(t, int64(55), secondLine.MetricSetFields["interest_ops"]) + + assert.Equal(t, int64(0), firstLine.MetricSetFields["queued"]) + assert.Equal(t, int64(11), secondLine.MetricSetFields["queued"]) + + assert.Equal(t, int64(1), firstLine.MetricSetFields["received"]) + assert.Equal(t, int64(22), secondLine.MetricSetFields["received"]) + + assert.Equal(t, int64(0), firstLine.MetricSetFields["sent"]) + assert.Equal(t, int64(333), secondLine.MetricSetFields["sent"]) +} diff --git a/metricbeat/module/zookeeper/connection/data.go b/metricbeat/module/zookeeper/connection/data.go new file mode 100644 index 000000000000..a30c61e62ba8 --- /dev/null +++ b/metricbeat/module/zookeeper/connection/data.go @@ -0,0 +1,110 @@ +// Licensed to Elasticsearch B.V. under one or more contributor +// license agreements. See the NOTICE file distributed with +// this work for additional information regarding copyright +// ownership. Elasticsearch B.V. licenses this file to you under +// the Apache License, Version 2.0 (the "License"); you may +// not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package connection + +import ( + "bufio" + "io" + "regexp" + "strconv" + + "github.com/pkg/errors" + + "github.com/elastic/beats/metricbeat/mb" + + "github.com/elastic/beats/libbeat/common" +) + +var capturer = regexp.MustCompile(`/(?P.*):(?P\d+)\[(?P\d*)]\(queued=(?P\d*),recved=(?P\d*),sent=(?P\d*)\)`) + +func (m *MetricSet) parseCons(i io.Reader) ([]mb.Event, error) { + scanner := bufio.NewScanner(i) + + result := make([]mb.Event, 0) + + for scanner.Scan() { + metricsetFields := common.MapStr{} + rootFields := common.MapStr{} + line := scanner.Text() + + oneParsingIsCorrect := false + keyMap, err := lineToMap(line) + if err != nil { + m.Logger().Debugf(err.Error()) + continue + } + + for k, v := range keyMap { + if k == "ip" { + if _, err := rootFields.Put("client.ip", v); err != nil { + m.Logger().Debugf("%v. Error placing key 'ip' on event", err) + } else { + oneParsingIsCorrect = true + } + } else if k == "port" { + m.checkRegexAndSetInt(rootFields, v, "client.port", &oneParsingIsCorrect) + } else { + m.checkRegexAndSetInt(metricsetFields, v, k, &oneParsingIsCorrect) + } + } + + if oneParsingIsCorrect { + result = append(result, mb.Event{MetricSetFields: metricsetFields, RootFields: rootFields}) + } else { + m.Logger().Debug("no field from incoming string '%s' could be parsed", line) + } + } + + return result, nil +} + +func lineToMap(line string) (map[string]string, error) { + capturedPatterns := capturer.FindStringSubmatch(line) + if len(capturedPatterns) < 1 { + //Nothing captured + return nil, errors.Errorf("no data captured in '%s'", line) + } + + keyMap := make(map[string]string) + for i, name := range capturer.SubexpNames() { + if i != 0 && name != "" { + keyMap[name] = capturedPatterns[i] + } + } + + return keyMap, nil +} + +func (m *MetricSet) checkRegexAndSetInt(output common.MapStr, capturedData string, key string, correct *bool) { + if capturedData != "" { + n, err := strconv.ParseInt(capturedData, 10, 64) + if err != nil { + m.Logger().Errorf("parse error: %v. Cannot convert string to it", err) + return + } + if _, err = output.Put(key, n); err != nil { + m.Logger().Errorf("parse error: %v. Error putting key '%s' on event", err, key) + return + } + *correct = true + } else { + m.Logger().Errorf("parse error: empty data for key '%s'", key) + } + + return +} diff --git a/metricbeat/module/zookeeper/fields.go b/metricbeat/module/zookeeper/fields.go index 516bd6125f81..41a234d28608 100644 --- a/metricbeat/module/zookeeper/fields.go +++ b/metricbeat/module/zookeeper/fields.go @@ -32,5 +32,5 @@ func init() { // AssetZookeeper returns asset data. // This is the base64 encoded gzipped contents of ../metricbeat/module/zookeeper. func AssetZookeeper() string { - return "eJy0mE1v20gPx+/+FEQvvbT+ADk8QIE+h2LRLrDoXnpx6RFtERkNlRnKjvPpFzPSyJItpU78cgosi/yRw5f/5DM80uEBXkQeiWryCwBltfQAH36J/JW++7AAKCgYz7WyuAf43wIAoH8OFalnE8CItWSUClgfQEuCjTT+syXV+CNxrOLZbcFIVaErwnIBEErxujLiNrx9gA3aQAsAT5Yw0ANscQGwYbJFeEheP4PDisbE8aOHOv7cS1N330wgx8/v/s3fYMQpsgsJNkfhqRbfBdHH2L8+ZI+fIduQr3J6fGkK7xXEhBkNXEB4mub2vZGpDnk5+HKc3/w5jWUYTylB41+jhzmuRzrsxRcnz16Jblw/2fZy0jPWtZdnrlBpVaDiKvDLNIYVt30bw5ejbYhmQTYDruhtmsmikjOHJe5OHb6bZEcet5Qtw5p0T+SAXKBqbSklKQA7qNhaDmRkUIVjOqpLqsijDSsjjdMbIf5oqjX5mKLeAbw4KWgGYyPWyp58uLn/3jKEmKOuDUzjPTlNmZomqvB5tWFLq+xJ/E0z9B2fuWoqcEdStgRHbwEwkRewEZ+gj9VWezEUZnKZC67C5xuz5oK7qLJ6DHa3wmD3dgzXVCu0vKO4OByZaPz2VTawDSqDk9ISFdD3FWcPkGimYaUmd9eq+zFfbdF3bo8LK00aDYquYLddeXpqKOjtUztwAtlJm1ZHVMRsryljHvecsU1Q8tPcNZpH0rD0ZIh3dLqMrmc+5s+R7sU/ZpeQXb4OFugOJz4PFd3NAFF7uuHgzO2PtrMOyXo8SYPeH+KJj5uoX2z9MJ+mDeR35FdBUW8oPv4RS3HWjBsjM82QHJyhYnW/tdY6GGy3XujtS3KAEJftKCHAASxhMdcUO/KBZXpWo2U8jaFGLduUs6Hl9NsXy7rudUBXwLphW0BQ33Z8G9Y08x7VlHcakMk2hcHgDqQgbR1YMWgvHZNJ+NyJshVVZzL/j3zjlnnb7eNj+9I7LhzB79JFpb1kfLzqlnHtOh8sb8vkdHjSne12vcQoztJ0pnMmGU7TOBfT0N75PeHVmM7iyrcDrGLBxfiUKwLFR3K9lOxOUAU8hVpcChS7TOQ1O4t4rizfhpj15D0Rz1TnGxE7rXljxB5PindvqO9xskegnmAJ3+Lo7HfSJ9CSA1R4AGItyUeJ1M5+EN8vjSX8HR/uOdAnYI0LIikttOJoWkxfN8h+iqId3HjS7PqTsryyuXvJ+NRQQwWgjhL3MyaKng1REeCFvLT7c3C6nWILUImnkQJ1XdIwShOVPGQnA7pKak5Ek+3lMfvKgHq3mJxwG21d4LJb56tiTohNPBi5/hoFS1fjv/I/4fKSGAxqdtCE6Vp9eebpbF/QYv86fmoIdmibCQz16AKm1QPfvsYaouQtro3AMU2ySe1YiymTpEFITZM6NZUMBcW15VAOVnbbn/HnHGJUaZoUpOQrdpR+o1TV4tGC+IKSPorrq0S3nemja3t1EGrIiehAuQtw5t9Kp08u9fv/lLQLM/8lJznw1vGGqdUiNXmWIhLuS45HkHs5NmvHv/gvAAD//1f3gz4=" + return "eJy0WM2O2zgMvucpiF56afMAOSxQbPdQLNrFFt1LLy4jM7EQWXQlOj/z9AvJln8SeyYz4/EpiCx+Hyn+fPJHONBlAw/MB6KK3ApAtBjawLufzH/H/96tAHLyyulKNNsN/LECAOjWoSRxWnlQbAwpoRy2F5CCYMe1+2hIJLzEVgs7bfeguCzR5n69AvAFO8kU253eb2CHxtMKwJEh9LSBPa4AdppM7jcR9SNYLGnMODxyqcLrjuuq/WeCcnh+dTt/gWIrqK2PZJMXjip2rROdj932IffwDLkN+Sm2llQA75amSIanc3ZLgoP/ZxxoWCTrfvD/NZchH22FHHnJuPKjFxIrw3Z/tfAIgfB8aU3CtcmE+bummvKF0P6NxmY87zEdKdLHxVC/t+aexPVkZSHMP3uosdmEVVpxT2bVIyC/goE7sv+6hJt9V4kYy2E9lc57vDM3C/YSfk3G70CXE7vr83wihH1vSrbXk8hYVY7PukShLEfBzOuHaRrPP8ZPvW0IZoF3A14BbZqTQSGrLms8XgO+mMmRHO4pWQ595kRkgayncmsoBsmDtlBqY7QnxYMON2ZHVUElOTQ+U1wvlvPf6nJLLoSoA4AHyznN0NixMXwit1Qv6/E7y+BDjNoyULVzZCVGappRiedspw1lCYndohH6imdd1iXYnqk2BD2aB4zMc9ixi6T7bKscK/IzsUwJV+J5Ya4p4e7KrI6GtkvR0Pb5NGxdZmj0kbK5lr9Elg1sg/DgpKRAAXRdxpkLRDbTZLki+6ZZ920+2wJ2Ko87M41r8YI213afOfpdk5flQzsAgQTShNUS5SHaW0o0+zmnTO2F3DTvCtWBxK8XFhc95z5+luTE7pAgOz3zOLEF1cc9pALcDCFqTtdfrFr+aFvrEK2Hk1To3CWc+LiIusHWNfNptp7ckVzmBWVB8fGdDYVeMy6MxGmGycUqyrO3G2sNwGC6dULvVJAFhDBsRwEB7cEQ5nNFcSTnx9ebnikajdc+VChFE3KtaD29+25Z124HtDlsa21y8OKaim/cmuZ8QlHFGzXIaJv8oHF7EuAmDwwrNPe2ySh83ohlI6puZP6T/MYl87zbx/tm0wsuHN4d40WluWS8f9Ut47XjfDC8jSYrw5NubTfjJXhxE6YbnTPJ4TqMcz4N7d3eEx716cavdDvAMiRc8E90SSB4INtJyfYEhcGRr9hGR7GNRBqzsxRvleXzKCY9+ZYUb1TnMym2WnNhih09zl88ob6Gzh4IdQzW8CW0zm4mfQAptIcSL0BaCnJBIjW9H9h1Q2MN/4TFk/b0AbSEARGVFhq2NC2mX9fIfrCgGdx4Yu96Slm+srg7ydh8vQKUUeB+hEDRWRHlHh7IcTM/B6fbKjYPJTsaKVDbBg2DNBFOTXb571gT3iR7qc0+0qBeLCYnYIOtOyDbcZ7lc0JsYmEE/TkIljbHf6YPvGlIDBq1tlD76Vx9OOvpaN9RYv9Z/bsmOKKpJ2iIQ+sxjh748jnkEEW0MDa8DmHiXSzHilURJQ1CLJpYqTFlyAtujfbFYGQ39Rle1z54FbtJTkKu1JbiO0JlxQ4NsMsp6qMwvgq0+5k6em2tDlz1KRAtUd06OPNZ6XrlXty/YtDujPynFGSv91bvNDVapCKnOQ8MT4UOR5BqORRry3/1fwAAAP//QtgX7Q==" } diff --git a/metricbeat/tests/system/test_zookeeper.py b/metricbeat/tests/system/test_zookeeper.py index 6e3baadea639..5aebfae35e49 100644 --- a/metricbeat/tests/system/test_zookeeper.py +++ b/metricbeat/tests/system/test_zookeeper.py @@ -78,6 +78,34 @@ def test_output(self): self.assert_fields_are_documented(evt) + @unittest.skipUnless(metricbeat.INTEGRATION_TESTS, "integration test") + @attr('integration') + def test_connection(self): + """ + ZooKeeper server module outputs an event. + """ + self.render_config_template(modules=[{ + "name": "zookeeper", + "metricsets": ["connection"], + "hosts": self.get_hosts(), + "period": "5s" + }]) + proc = self.start_beat() + self.wait_until(lambda: self.output_lines() > 0) + proc.check_kill_and_wait() + self.assert_no_logged_warnings() + + output = self.read_output_json() + self.assertEqual(len(output), 1) + evt = output[0] + + self.assertItemsEqual(self.de_dot(ZK_FIELDS + ["client"]), evt.keys()) + zk_conns = evt["zookeeper"]["connection"] + + assert zk_conns["queued"] >= 0 + + self.assert_fields_are_documented(evt) + def get_hosts(self): return [os.getenv('ZOOKEEPER_HOST', 'localhost') + ':' + os.getenv('ZOOKEEPER_PORT', '2181')]