From f3f189c3203643183444827d80636a245c1e5bc0 Mon Sep 17 00:00:00 2001 From: Vijay Samuel Date: Wed, 19 Apr 2017 23:06:28 -0700 Subject: [PATCH] Adding dropwizard module to Metricbeat (#4022) --- CHANGELOG.asciidoc | 1 + metricbeat/docker-compose.yml | 5 + metricbeat/docs/fields.asciidoc | 14 ++ metricbeat/docs/modules/dropwizard.asciidoc | 38 ++++++ .../modules/dropwizard/collector.asciidoc | 19 +++ metricbeat/docs/modules_list.asciidoc | 2 + metricbeat/include/list.go | 2 + metricbeat/metricbeat.full.yml | 9 ++ .../module/dropwizard/_meta/.dockerignore | 1 + metricbeat/module/dropwizard/_meta/Dockerfile | 8 ++ metricbeat/module/dropwizard/_meta/config.yml | 7 + .../module/dropwizard/_meta/docs.asciidoc | 4 + metricbeat/module/dropwizard/_meta/env | 2 + metricbeat/module/dropwizard/_meta/fields.yml | 12 ++ .../module/dropwizard/_meta/test/.gitignore | 1 + .../module/dropwizard/_meta/test/pom.xml | 40 ++++++ .../MetricsServletContextListener.java | 48 +++++++ .../java/io/test/dropwizard/TestServlet.java | 39 ++++++ .../test/src/main/webapp/WEB-INF/web.xml | 50 ++++++++ .../dropwizard/collector/_meta/data.json | 19 +++ .../dropwizard/collector/_meta/docs.asciidoc | 3 + .../dropwizard/collector/_meta/fields.yml | 0 .../module/dropwizard/collector/collector.go | 94 ++++++++++++++ .../collector/collector_integration_test.go | 91 +++++++++++++ .../module/dropwizard/collector/data.go | 121 ++++++++++++++++++ metricbeat/module/dropwizard/doc.go | 4 + .../tests/system/config/metricbeat.yml.j2 | 4 + metricbeat/tests/system/test_dropwizard.py | 31 +++++ 28 files changed, 669 insertions(+) create mode 100644 metricbeat/docs/modules/dropwizard.asciidoc create mode 100644 metricbeat/docs/modules/dropwizard/collector.asciidoc create mode 100644 metricbeat/module/dropwizard/_meta/.dockerignore create mode 100644 metricbeat/module/dropwizard/_meta/Dockerfile create mode 100644 metricbeat/module/dropwizard/_meta/config.yml create mode 100644 metricbeat/module/dropwizard/_meta/docs.asciidoc create mode 100644 metricbeat/module/dropwizard/_meta/env create mode 100644 metricbeat/module/dropwizard/_meta/fields.yml create mode 100644 metricbeat/module/dropwizard/_meta/test/.gitignore create mode 100644 metricbeat/module/dropwizard/_meta/test/pom.xml create mode 100644 metricbeat/module/dropwizard/_meta/test/src/main/java/io/test/dropwizard/MetricsServletContextListener.java create mode 100644 metricbeat/module/dropwizard/_meta/test/src/main/java/io/test/dropwizard/TestServlet.java create mode 100644 metricbeat/module/dropwizard/_meta/test/src/main/webapp/WEB-INF/web.xml create mode 100644 metricbeat/module/dropwizard/collector/_meta/data.json create mode 100644 metricbeat/module/dropwizard/collector/_meta/docs.asciidoc create mode 100644 metricbeat/module/dropwizard/collector/_meta/fields.yml create mode 100644 metricbeat/module/dropwizard/collector/collector.go create mode 100644 metricbeat/module/dropwizard/collector/collector_integration_test.go create mode 100644 metricbeat/module/dropwizard/collector/data.go create mode 100644 metricbeat/module/dropwizard/doc.go create mode 100644 metricbeat/tests/system/test_dropwizard.py diff --git a/CHANGELOG.asciidoc b/CHANGELOG.asciidoc index 48fb33db0a3b..bf14f3936229 100644 --- a/CHANGELOG.asciidoc +++ b/CHANGELOG.asciidoc @@ -133,6 +133,7 @@ https://github.com/elastic/beats/compare/v5.1.1...master[Check the HEAD diff] - Adding support for custom http headers and TLS for metricbeat modules {pull}3945[3945] - Add new MetricSet interfaces for developers (`Closer`, `ReportingFetcher`, and `PushMetricSet`). {pull}3908[3908] - Add kubelet module {pull}3916[3916] +- Add dropwizard module {pull}4022[4022] *Packetbeat* - Add `fields` and `fields_under_root` to packetbeat protocols configurations. {pull}3518[3518] diff --git a/metricbeat/docker-compose.yml b/metricbeat/docker-compose.yml index b925b3446421..dd256ca72a4d 100644 --- a/metricbeat/docker-compose.yml +++ b/metricbeat/docker-compose.yml @@ -19,6 +19,7 @@ services: - ${PWD}/module/apache/_meta/env - ${PWD}/module/ceph/_meta/env - ${PWD}/module/couchbase/_meta/env + - ${PWD}/module/dropwizard/_meta/env - ${PWD}/module/elasticsearch/_meta/env - ${PWD}/module/haproxy/_meta/env - ${PWD}/module/jolokia/_meta/env @@ -42,6 +43,7 @@ services: apache: { condition: service_healthy } ceph: { condition: service_healthy } couchbase: { condition: service_healthy } + dropwizard: { condition: service_healthy } elasticsearch: { condition: service_healthy } haproxy: { condition: service_healthy } jolokia: { condition: service_healthy } @@ -67,6 +69,9 @@ services: couchbase: build: ${PWD}/module/couchbase/_meta + dropwizard: + build: ${PWD}/module/dropwizard/_meta + elasticsearch: extends: file: ${ES_BEATS}/testing/environments/${TESTING_ENVIRONMENT}.yml diff --git a/metricbeat/docs/fields.asciidoc b/metricbeat/docs/fields.asciidoc index b733832c4dd0..02c52a61a739 100644 --- a/metricbeat/docs/fields.asciidoc +++ b/metricbeat/docs/fields.asciidoc @@ -19,6 +19,7 @@ grouped in the following categories: * <> * <> * <> +* <> * <> * <> * <> @@ -1875,6 +1876,19 @@ type: long Total number of outgoing packets. +[[exported-fields-dropwizard]] +== Dropwizard Fields + +beta[] +Stats collected from Dropwizard. + + + +[float] +== dropwizard Fields + + + [[exported-fields-elasticsearch]] == elasticsearch Fields diff --git a/metricbeat/docs/modules/dropwizard.asciidoc b/metricbeat/docs/modules/dropwizard.asciidoc new file mode 100644 index 000000000000..eb0ab3f47679 --- /dev/null +++ b/metricbeat/docs/modules/dropwizard.asciidoc @@ -0,0 +1,38 @@ +//// +This file is generated! See scripts/docs_collector.py +//// + +[[metricbeat-module-dropwizard]] +== dropwizard Module + +This is the http://dropwizard.io[Dropwizard] Module. + + + +[float] +=== Example Configuration + +The Dropwizard module supports the standard configuration options that are described +in <>. Here is an example configuration: + +[source,yaml] +---- +metricbeat.modules: +#- module: dropwizard + #metricsets: ["collector"] + #enabled: true + #period: 10s + #hosts: ["localhost:8080"] + #metrics_path: /metrics/metrics + #namespace: example +---- + +[float] +=== Metricsets + +The following metricsets are available: + +* <> + +include::dropwizard/collector.asciidoc[] + diff --git a/metricbeat/docs/modules/dropwizard/collector.asciidoc b/metricbeat/docs/modules/dropwizard/collector.asciidoc new file mode 100644 index 000000000000..ed0acda2a2a0 --- /dev/null +++ b/metricbeat/docs/modules/dropwizard/collector.asciidoc @@ -0,0 +1,19 @@ +//// +This file is generated! See scripts/docs_collector.py +//// + +[[metricbeat-metricset-dropwizard-collector]] +include::../../../module/dropwizard/collector/_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/dropwizard/collector/_meta/data.json[] +---- diff --git a/metricbeat/docs/modules_list.asciidoc b/metricbeat/docs/modules_list.asciidoc index 07ab03812b04..418728dc5540 100644 --- a/metricbeat/docs/modules_list.asciidoc +++ b/metricbeat/docs/modules_list.asciidoc @@ -6,6 +6,7 @@ This file is generated! See scripts/docs_collector.py * <> * <> * <> + * <> * <> * <> * <> @@ -32,6 +33,7 @@ include::modules/apache.asciidoc[] include::modules/ceph.asciidoc[] include::modules/couchbase.asciidoc[] include::modules/docker.asciidoc[] +include::modules/dropwizard.asciidoc[] include::modules/elasticsearch.asciidoc[] include::modules/golang.asciidoc[] include::modules/haproxy.asciidoc[] diff --git a/metricbeat/include/list.go b/metricbeat/include/list.go index 3a2229f7fabe..02cbf5922795 100644 --- a/metricbeat/include/list.go +++ b/metricbeat/include/list.go @@ -28,6 +28,8 @@ import ( _ "github.com/elastic/beats/metricbeat/module/docker/info" _ "github.com/elastic/beats/metricbeat/module/docker/memory" _ "github.com/elastic/beats/metricbeat/module/docker/network" + _ "github.com/elastic/beats/metricbeat/module/dropwizard" + _ "github.com/elastic/beats/metricbeat/module/dropwizard/collector" _ "github.com/elastic/beats/metricbeat/module/elasticsearch" _ "github.com/elastic/beats/metricbeat/module/elasticsearch/node" _ "github.com/elastic/beats/metricbeat/module/elasticsearch/node_stats" diff --git a/metricbeat/metricbeat.full.yml b/metricbeat/metricbeat.full.yml index bde477db46f2..f0fb2d849115 100644 --- a/metricbeat/metricbeat.full.yml +++ b/metricbeat/metricbeat.full.yml @@ -124,6 +124,15 @@ metricbeat.modules: #certificate: "/etc/pki/client/cert.pem" #key: "/etc/pki/client/cert.key" +#----------------------------- Dropwizard Module ----------------------------- +#- module: dropwizard + #metricsets: ["collector"] + #enabled: true + #period: 10s + #hosts: ["localhost:8080"] + #metrics_path: /metrics/metrics + #namespace: example + #---------------------------- elasticsearch Module --------------------------- #- module: elasticsearch # metricsets: ["node", "node_stats", "stats"] diff --git a/metricbeat/module/dropwizard/_meta/.dockerignore b/metricbeat/module/dropwizard/_meta/.dockerignore new file mode 100644 index 000000000000..bb0e316a4790 --- /dev/null +++ b/metricbeat/module/dropwizard/_meta/.dockerignore @@ -0,0 +1 @@ +test/target diff --git a/metricbeat/module/dropwizard/_meta/Dockerfile b/metricbeat/module/dropwizard/_meta/Dockerfile new file mode 100644 index 000000000000..4c544812b27d --- /dev/null +++ b/metricbeat/module/dropwizard/_meta/Dockerfile @@ -0,0 +1,8 @@ +FROM maven:3.3-jdk-8 +COPY test /test + +HEALTHCHECK CMD curl -f http://localhost:8080/test/helloworld +EXPOSE 8080 + +WORKDIR /test +CMD mvn jetty:run diff --git a/metricbeat/module/dropwizard/_meta/config.yml b/metricbeat/module/dropwizard/_meta/config.yml new file mode 100644 index 000000000000..9963d2ddc057 --- /dev/null +++ b/metricbeat/module/dropwizard/_meta/config.yml @@ -0,0 +1,7 @@ +#- module: dropwizard + #metricsets: ["collector"] + #enabled: true + #period: 10s + #hosts: ["localhost:8080"] + #metrics_path: /metrics/metrics + #namespace: example diff --git a/metricbeat/module/dropwizard/_meta/docs.asciidoc b/metricbeat/module/dropwizard/_meta/docs.asciidoc new file mode 100644 index 000000000000..21ade09313d6 --- /dev/null +++ b/metricbeat/module/dropwizard/_meta/docs.asciidoc @@ -0,0 +1,4 @@ +== dropwizard Module + +This is the http://dropwizard.io[Dropwizard] Module. + diff --git a/metricbeat/module/dropwizard/_meta/env b/metricbeat/module/dropwizard/_meta/env new file mode 100644 index 000000000000..771807862fd8 --- /dev/null +++ b/metricbeat/module/dropwizard/_meta/env @@ -0,0 +1,2 @@ +DROPWIZARD_HOST=dropwizard +DROPWIZARD_PORT=8080 diff --git a/metricbeat/module/dropwizard/_meta/fields.yml b/metricbeat/module/dropwizard/_meta/fields.yml new file mode 100644 index 000000000000..d76d0baa9484 --- /dev/null +++ b/metricbeat/module/dropwizard/_meta/fields.yml @@ -0,0 +1,12 @@ +- key: dropwizard + title: "Dropwizard" + description: > + beta[] + + Stats collected from Dropwizard. + short_config: false + fields: + - name: dropwizard + type: group + description: > + fields: diff --git a/metricbeat/module/dropwizard/_meta/test/.gitignore b/metricbeat/module/dropwizard/_meta/test/.gitignore new file mode 100644 index 000000000000..eb5a316cbd19 --- /dev/null +++ b/metricbeat/module/dropwizard/_meta/test/.gitignore @@ -0,0 +1 @@ +target diff --git a/metricbeat/module/dropwizard/_meta/test/pom.xml b/metricbeat/module/dropwizard/_meta/test/pom.xml new file mode 100644 index 000000000000..430125802b20 --- /dev/null +++ b/metricbeat/module/dropwizard/_meta/test/pom.xml @@ -0,0 +1,40 @@ + + + 4.0.0 + io.test.dropwizard + test + 1.0-SNAPSHOT + war + Test Webapp for dropwizard metrics + + + javax.servlet + servlet-api + 2.5 + provided + + + io.dropwizard.metrics + metrics-servlets + 3.1.0 + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 2.3.2 + + 1.6 + 1.6 + + + + org.mortbay.jetty + maven-jetty-plugin + + + + diff --git a/metricbeat/module/dropwizard/_meta/test/src/main/java/io/test/dropwizard/MetricsServletContextListener.java b/metricbeat/module/dropwizard/_meta/test/src/main/java/io/test/dropwizard/MetricsServletContextListener.java new file mode 100644 index 000000000000..264d8d8e6d5d --- /dev/null +++ b/metricbeat/module/dropwizard/_meta/test/src/main/java/io/test/dropwizard/MetricsServletContextListener.java @@ -0,0 +1,48 @@ +package io.test.dropwizard; + +import com.codahale.metrics.Counter; +import com.codahale.metrics.Gauge; +import com.codahale.metrics.Meter; +import com.codahale.metrics.MetricRegistry; +import com.codahale.metrics.Timer; +import com.codahale.metrics.servlets.MetricsServlet; + +/** + * + * MetricsServletContextListener is a listener class that needs to be added to all assertion + * web application's web.xml in order to expose the MetricsRegistry which maintains all the + * metrics that are being tracked. + * + */ + +public class MetricsServletContextListener extends MetricsServlet.ContextListener { + + public static MetricRegistry METRIC_REGISTRY = new MetricRegistry(); + + static { + Counter c = new Counter(); + c.inc(); + METRIC_REGISTRY.register("my_counter{this=that}", c); + METRIC_REGISTRY.register("my_meter{this=that}", new Meter()); + + METRIC_REGISTRY.register("my_timer", new Timer()); + METRIC_REGISTRY.histogram("my_histogram"); + METRIC_REGISTRY.register("my_gauge", new Gauge() { + + @Override + public Integer getValue() { + // TODO Auto-generated method stub + return null; + } + + }); + + } + + @Override + protected MetricRegistry getMetricRegistry() { + return METRIC_REGISTRY; + } + + +} diff --git a/metricbeat/module/dropwizard/_meta/test/src/main/java/io/test/dropwizard/TestServlet.java b/metricbeat/module/dropwizard/_meta/test/src/main/java/io/test/dropwizard/TestServlet.java new file mode 100644 index 000000000000..e651c4aa4463 --- /dev/null +++ b/metricbeat/module/dropwizard/_meta/test/src/main/java/io/test/dropwizard/TestServlet.java @@ -0,0 +1,39 @@ +package io.test.dropwizard; + +import java.io.Closeable; +import java.io.IOException; +import java.io.PrintWriter; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + + +@SuppressWarnings("serial") +public class TestServlet extends HttpServlet { + @SuppressWarnings("unchecked") + @Override + protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { + PrintWriter out = null; + try { + out = new PrintWriter(resp.getWriter()); + out.println("hello world"); + out.flush(); + } finally { + close(out); + } + } + + private static void close(Closeable c) { + if (c == null) { + return; + } + + try { + c.close(); + } catch (IOException ignore) { + /* ignore */ + } + } +} diff --git a/metricbeat/module/dropwizard/_meta/test/src/main/webapp/WEB-INF/web.xml b/metricbeat/module/dropwizard/_meta/test/src/main/webapp/WEB-INF/web.xml new file mode 100644 index 000000000000..783c271fac46 --- /dev/null +++ b/metricbeat/module/dropwizard/_meta/test/src/main/webapp/WEB-INF/web.xml @@ -0,0 +1,50 @@ + + + Test Dropwizard + + + HelloServlet + io.test.dropwizard.TestServlet + + + + HelloServlet + /helloworld + + + + io.test.dropwizard.MetricsServletContextListener + + + + CodahaleMetrics + com.codahale.metrics.servlets.MetricsServlet + + metrics-uri + /metrics + + + ping-uri + /ping + + + healthcheck-uri + /health + + + threads-uri + /threads + + + + + CodahaleMetrics + /metrics/* + + + + diff --git a/metricbeat/module/dropwizard/collector/_meta/data.json b/metricbeat/module/dropwizard/collector/_meta/data.json new file mode 100644 index 000000000000..bee1cd731e31 --- /dev/null +++ b/metricbeat/module/dropwizard/collector/_meta/data.json @@ -0,0 +1,19 @@ +{ + "@timestamp": "2017-04-16T06:42:37.441Z", + "beat": { + "hostname": "beathost", + "name": "beathost", + "version": "6.0.0-alpha1" + }, + "dropwizard": { + "test": {} + }, + "metricset": { + "host": "localhost:8080", + "module": "dropwizard", + "name": "collector", + "namespace": "test", + "rtt": 8008 + }, + "type": "metricsets" +} diff --git a/metricbeat/module/dropwizard/collector/_meta/docs.asciidoc b/metricbeat/module/dropwizard/collector/_meta/docs.asciidoc new file mode 100644 index 000000000000..c27f157a72f8 --- /dev/null +++ b/metricbeat/module/dropwizard/collector/_meta/docs.asciidoc @@ -0,0 +1,3 @@ +=== dropwizard collector MetricSet + +This is the collector metricset of the module dropwizard. diff --git a/metricbeat/module/dropwizard/collector/_meta/fields.yml b/metricbeat/module/dropwizard/collector/_meta/fields.yml new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/metricbeat/module/dropwizard/collector/collector.go b/metricbeat/module/dropwizard/collector/collector.go new file mode 100644 index 000000000000..a4b35e03bdec --- /dev/null +++ b/metricbeat/module/dropwizard/collector/collector.go @@ -0,0 +1,94 @@ +package collector + +import ( + "encoding/json" + "github.com/elastic/beats/libbeat/common" + "github.com/elastic/beats/libbeat/logp" + "github.com/elastic/beats/metricbeat/helper" + "github.com/elastic/beats/metricbeat/mb" + "github.com/elastic/beats/metricbeat/mb/parse" + "strings" +) + +const ( + defaultScheme = "http" + defaultPath = "/metrics/metrics" +) + +var ( + hostParser = parse.URLHostParserBuilder{ + DefaultScheme: defaultScheme, + DefaultPath: defaultPath, + PathConfigKey: "metrics_path", + }.Build() +) + +// 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("dropwizard", "collector", New, hostParser); 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 + namespace 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) { + logp.Beta("The dropwizard collector metricset is beta") + config := struct { + Namespace string `config:"namespace" validate:"required"` + }{} + + if err := base.Module().UnpackConfig(&config); err != nil { + return nil, err + } + + return &MetricSet{ + BaseMetricSet: base, + http: helper.NewHTTP(base), + namespace: config.Namespace, + }, 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) { + body, err := m.http.FetchContent() + if err != nil { + return nil, err + } + dw := map[string]interface{}{} + + d := json.NewDecoder(strings.NewReader(string(body))) + d.UseNumber() + + err = d.Decode(&dw) + if err != nil { + return nil, err + } + + eventList := eventMapping(dw) + + // Converts hash list to slice + events := []common.MapStr{} + for _, e := range eventList { + e["_namespace"] = m.namespace + events = append(events, e) + } + + return events, err + +} diff --git a/metricbeat/module/dropwizard/collector/collector_integration_test.go b/metricbeat/module/dropwizard/collector/collector_integration_test.go new file mode 100644 index 000000000000..d5825dcc8d36 --- /dev/null +++ b/metricbeat/module/dropwizard/collector/collector_integration_test.go @@ -0,0 +1,91 @@ +// +build integration + +package collector + +import ( + "os" + "testing" + + "github.com/elastic/beats/libbeat/common" + mbtest "github.com/elastic/beats/metricbeat/mb/testing" + "github.com/stretchr/testify/assert" +) + +func TestFetch(t *testing.T) { + f := mbtest.NewEventsFetcher(t, getConfig()) + events, err := f.Fetch() + + hasTag := false + doesntHaveTag := false + for _, event := range events { + + ok, _ := event.HasKey("my_histogram") + if ok { + _, err := event.GetValue("tags") + if err == nil { + t.Fatal("write", "my_counter not supposed to have tags") + } + doesntHaveTag = true + } + + ok, _ = event.HasKey("my_counter") + if ok { + tagsRaw, err := event.GetValue("tags") + if err != nil { + t.Fatal("write", err) + } else { + tags, ok := tagsRaw.(common.MapStr) + if !ok { + t.Fatal("write", "unable to cast tags to common.MapStr") + } else { + assert.Equal(t, len(tags), 1) + hasTag = true + } + } + } + } + assert.Equal(t, hasTag, true) + assert.Equal(t, doesntHaveTag, true) + if !assert.NoError(t, err) { + t.FailNow() + } + + t.Logf("%s/%s event: %+v", f.Module().Name(), f.Name(), events) +} + +func TestData(t *testing.T) { + f := mbtest.NewEventsFetcher(t, getConfig()) + err := mbtest.WriteEvents(f, t) + if err != nil { + t.Fatal("write", err) + } +} + +func getEnvHost() string { + host := os.Getenv("DROPWIZARD_HOST") + + if len(host) == 0 { + host = "127.0.0.1" + } + return host +} + +func getEnvPort() string { + port := os.Getenv("DROPWIZARD_PORT") + + if len(port) == 0 { + port = "8080" + } + return port +} + +func getConfig() map[string]interface{} { + return map[string]interface{}{ + "module": "dropwizard", + "metricsets": []string{"collector"}, + "hosts": []string{getEnvHost() + ":" + getEnvPort()}, + "namespace": "testnamespace", + "metrics_path": "/test/metrics", + "enabled": true, + } +} diff --git a/metricbeat/module/dropwizard/collector/data.go b/metricbeat/module/dropwizard/collector/data.go new file mode 100644 index 000000000000..9c795d453d59 --- /dev/null +++ b/metricbeat/module/dropwizard/collector/data.go @@ -0,0 +1,121 @@ +package collector + +import ( + "strings" + + "encoding/json" + "github.com/elastic/beats/libbeat/common" +) + +type DropWizardEvent struct { + key string + value common.MapStr + tags common.MapStr + tagHash string +} + +// NewPromEvent creates a prometheus event based on the given string +func eventMapping(metrics map[string]interface{}) map[string]common.MapStr { + eventList := map[string]common.MapStr{} + + for _, metricSet := range metrics { + switch t := metricSet.(type) { + case map[string]interface{}: + for key, value := range t { + name, tags := splitTagsFromMetricName(key) + valueMap := common.MapStr{} + + metric, _ := value.(map[string]interface{}) + for k, v := range metric { + switch v.(type) { + case string: + valueMap[k] = v + + case json.Number: + valueMap[k] = convertValue(v.(json.Number)) + } + + } + + dropEvent := DropWizardEvent{ + key: name, + value: valueMap, + } + + if len(tags) != 0 { + dropEvent.tags = tags + dropEvent.tagHash = tags.String() + } else { + dropEvent.tagHash = "_" + } + + if _, ok := eventList[dropEvent.tagHash]; !ok { + eventList[dropEvent.tagHash] = common.MapStr{} + + // Add labels + if len(dropEvent.tags) > 0 { + eventList[dropEvent.tagHash]["tags"] = dropEvent.tags + } + + } + eventList[dropEvent.tagHash][dropEvent.key] = dropEvent.value + + } + + default: + continue + } + + } + + return eventList +} + +func splitTagsFromMetricName(metricName string) (string, common.MapStr) { + if metricName == "" { + return "", nil + } + + index := strings.Index(metricName, "{") + if index == -1 { + return metricName, nil + } + + key := metricName[:index] + tags := common.MapStr{} + + tagStr := metricName[index+1 : len(metricName)-1] + + for { + dobreak := false + ind := strings.Index(tagStr, ",") + eqPos := strings.Index(tagStr, "=") + if ind == -1 { + tags[tagStr[:eqPos]] = tagStr[eqPos+1:] + dobreak = true + } else { + tags[tagStr[:eqPos]] = tagStr[eqPos+1 : ind] + tagStr = tagStr[ind+2:] + } + + if dobreak == true { + break + } + } + + return key, tags +} + +// convertValue takes the input string and converts it to int of float +func convertValue(value json.Number) interface{} { + + if i, err := value.Int64(); err == nil { + return i + } + + if f, err := value.Float64(); err == nil { + return f + } + + return value.String() +} diff --git a/metricbeat/module/dropwizard/doc.go b/metricbeat/module/dropwizard/doc.go new file mode 100644 index 000000000000..f7be050f8242 --- /dev/null +++ b/metricbeat/module/dropwizard/doc.go @@ -0,0 +1,4 @@ +/* +Package dropwizard is a Metricbeat module that contains MetricSets. +*/ +package dropwizard diff --git a/metricbeat/tests/system/config/metricbeat.yml.j2 b/metricbeat/tests/system/config/metricbeat.yml.j2 index 33eb3e6a4289..2665e2f07eee 100644 --- a/metricbeat/tests/system/config/metricbeat.yml.j2 +++ b/metricbeat/tests/system/config/metricbeat.yml.j2 @@ -37,6 +37,10 @@ metricbeat.modules: period: {{ m.period }} {% endif -%} + {% if m.path -%} + metrics_path: {{ m.path }} + {% endif -%} + {% if m.timeout -%} timeout: {{ m.timeout }} {% endif -%} diff --git a/metricbeat/tests/system/test_dropwizard.py b/metricbeat/tests/system/test_dropwizard.py new file mode 100644 index 000000000000..4c202daea8a7 --- /dev/null +++ b/metricbeat/tests/system/test_dropwizard.py @@ -0,0 +1,31 @@ +import os +import metricbeat +import unittest + + +class Test(metricbeat.BaseTest): + + @unittest.skipUnless(metricbeat.INTEGRATION_TESTS, "integration test") + def test_dropwizard(self): + """ + dropwizard metricset test + """ + + self.render_config_template(modules=[{ + "name": "dropwizard", + "metricsets": ["collector"], + "hosts": self.get_hosts(), + "path": "/test/metrics", + "period": "1s", + "namespace": "test", + }]) + proc = self.start_beat() + self.wait_until(lambda: self.output_lines() > 0, max_timeout=10) + proc.check_kill_and_wait() + + output = self.read_output_json() + self.assertTrue(len(output) >= 1) + + def get_hosts(self): + return [os.getenv('DROPWIZARD_HOST', 'localhost') + ':' + + os.getenv('DROPWIZARD_PORT', '8080')]