From ad647c64b24adba83f250c0744f0c8bff5780464 Mon Sep 17 00:00:00 2001 From: Eben Freeman Date: Thu, 23 Feb 2017 16:34:16 -0800 Subject: [PATCH 1/2] Add honeycomb metrics/events sink Remove unused SendMessage function Don't send empty batches Remove "labels" prefix from metric metadata; omit cumulative metrics honeycomb should grab write key from environ Add honeycomb common test Tests are now passing uncomment vet. this is an upstream issue Tests are now passing uncomment vet. this is an upstream issue Adding confugration instructions for honeycomb Adding honeycomb test for metrics update honeycomb Client to be interface to make testing easier. add metrics tests the event test found a bug. wooo. fixed and added test fixes per eben PR: no global. use batchpoints --- common/honeycomb/dummy_honeycomb.go | 40 ++++++ common/honeycomb/honeycomb.go | 125 +++++++++++++++++ common/honeycomb/honeycomb_test.go | 60 ++++++++ docs/sink-configuration.md | 18 +++ events/sinks/factory.go | 3 + events/sinks/honeycomb/driver.go | 95 +++++++++++++ events/sinks/honeycomb/honeycomb_test.go | 93 +++++++++++++ metrics/sinks/factory.go | 3 + metrics/sinks/honeycomb/driver.go | 95 +++++++++++++ metrics/sinks/honeycomb/honeycomb_test.go | 159 ++++++++++++++++++++++ 10 files changed, 691 insertions(+) create mode 100644 common/honeycomb/dummy_honeycomb.go create mode 100644 common/honeycomb/honeycomb.go create mode 100644 common/honeycomb/honeycomb_test.go create mode 100644 events/sinks/honeycomb/driver.go create mode 100644 events/sinks/honeycomb/honeycomb_test.go create mode 100644 metrics/sinks/honeycomb/driver.go create mode 100644 metrics/sinks/honeycomb/honeycomb_test.go diff --git a/common/honeycomb/dummy_honeycomb.go b/common/honeycomb/dummy_honeycomb.go new file mode 100644 index 0000000000..8b975e7056 --- /dev/null +++ b/common/honeycomb/dummy_honeycomb.go @@ -0,0 +1,40 @@ +// Copyright 2017 Google Inc. All Rights Reserved. +// +// Licensed 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 honeycomb + +type BatchPointsSavedToHoneycomb struct { + BatchPoint *BatchPoint +} + +type FakeHoneycombClient struct { + BatchPoints []*BatchPoint +} + +func NewFakeHoneycombClient() *FakeHoneycombClient { + return &FakeHoneycombClient{[]*BatchPoint{}} +} + +func (client *FakeHoneycombClient) SendBatch(batch Batch) error { + for _, batchpoint := range batch { + client.BatchPoints = append(client.BatchPoints, batchpoint) + } + return nil +} + +var Config = config{ + Dataset: "fake", + WriteKey: "fakekey", + APIHost: "fakehost", +} diff --git a/common/honeycomb/honeycomb.go b/common/honeycomb/honeycomb.go new file mode 100644 index 0000000000..0dbae83627 --- /dev/null +++ b/common/honeycomb/honeycomb.go @@ -0,0 +1,125 @@ +// Copyright 2017 Google Inc. All Rights Reserved. +// +// Licensed 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 honeycomb + +import ( + "bytes" + "encoding/json" + "errors" + "io" + "io/ioutil" + "net/http" + "net/url" + "os" + "path" + "time" + + "github.com/golang/glog" +) + +type config struct { + APIHost string + Dataset string + WriteKey string +} + +func BuildConfig(uri *url.URL) (*config, error) { + opts := uri.Query() + + config := &config{ + WriteKey: os.Getenv("HONEYCOMB_WRITEKEY"), + APIHost: "https://api.honeycomb.io/", + Dataset: "heapster", + } + + if len(opts["writekey"]) >= 1 { + config.WriteKey = opts["writekey"][0] + } + + if len(opts["apihost"]) >= 1 { + config.APIHost = opts["apihost"][0] + } + + if len(opts["dataset"]) >= 1 { + config.Dataset = opts["dataset"][0] + } + + if config.WriteKey == "" { + return nil, errors.New("Failed to find honeycomb API write key") + } + + return config, nil +} + +type Client interface { + SendBatch(batch Batch) error +} + +type HoneycombClient struct { + config config + httpClient http.Client +} + +func NewClient(uri *url.URL) (*HoneycombClient, error) { + config, err := BuildConfig(uri) + if err != nil { + return nil, err + } + return &HoneycombClient{config: *config}, nil +} + +type BatchPoint struct { + Data interface{} + Timestamp time.Time +} + +type Batch []*BatchPoint + +func (c *HoneycombClient) SendBatch(batch Batch) error { + if len(batch) == 0 { + // Nothing to send + return nil + } + buf := new(bytes.Buffer) + err := json.NewEncoder(buf).Encode(batch) + if err != nil { + return err + } + err = c.makeRequest(buf) + if err != nil { + return err + } + return nil +} + +func (c *HoneycombClient) makeRequest(body io.Reader) error { + url, err := url.Parse(c.config.APIHost) + if err != nil { + return err + } + url.Path = path.Join(url.Path, "/1/batch", c.config.Dataset) + req, err := http.NewRequest("POST", url.String(), body) + req.Header.Set("Content-Type", "application/json") + req.Header.Add("X-Honeycomb-Team", c.config.WriteKey) + + resp, err := c.httpClient.Do(req) + if err != nil { + glog.Warningf("Failed to send event: %v", err) + return err + } + defer resp.Body.Close() + ioutil.ReadAll(resp.Body) + return nil +} diff --git a/common/honeycomb/honeycomb_test.go b/common/honeycomb/honeycomb_test.go new file mode 100644 index 0000000000..7e1ef06d8f --- /dev/null +++ b/common/honeycomb/honeycomb_test.go @@ -0,0 +1,60 @@ +// Copyright 2017 Google Inc. All Rights Reserved. +// +// Licensed 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 honeycomb + +import ( + "net/http/httptest" + "net/url" + "testing" + "time" + + "github.com/stretchr/testify/assert" + util "k8s.io/client-go/util/testing" +) + +func TestHoneycombClientWrite(t *testing.T) { + handler := util.FakeHandler{ + StatusCode: 202, + ResponseBody: "", + T: t, + } + server := httptest.NewServer(&handler) + defer server.Close() + + stubURL, err := url.Parse("?writekey=testkey&dataset=testdataset&apihost=" + server.URL) + + assert.NoError(t, err) + + config, err := BuildConfig(stubURL) + + assert.Equal(t, config.WriteKey, "testkey") + assert.Equal(t, config.APIHost, server.URL) + assert.Equal(t, config.Dataset, "testdataset") + + assert.NoError(t, err) + + client, _ := NewClient(stubURL) + + err = client.SendBatch([]*BatchPoint{ + { + Data: "test", + Timestamp: time.Now(), + }, + }) + + assert.NoError(t, err) + + handler.ValidateRequestCount(t, 1) +} diff --git a/docs/sink-configuration.md b/docs/sink-configuration.md index 3b3ac4e62c..d5cac6d6b2 100644 --- a/docs/sink-configuration.md +++ b/docs/sink-configuration.md @@ -289,6 +289,24 @@ For example, The librato sink currently only works with accounts, which support [tagged metrics](https://www.librato.com/docs/kb/faq/account_questions/tags_or_sources/). +### Honeycomb + +This sink supports both monitoring metrics and events. + +To use the Honeycomb sink add the following flag: + + --sink="honeycomb:>" + +Options can be set in query string, like this: + +* `dataset` - Honeycomb Dataset to which to publish metrics/events +* `writekey` - Honeycomb Write Key for your account +* `apihost` - Option to send metrics to a different host (default: https://api.honeycomb.com) (optional) + +For example, + + --sink="honeycomb:?dataset=mydataset&writekey=secretwritekey" + ## Using multiple sinks Heapster can be configured to send k8s metrics and events to multiple sinks by specifying the`--sink=...` flag multiple times. diff --git a/events/sinks/factory.go b/events/sinks/factory.go index 7aca02383d..5ba260137d 100644 --- a/events/sinks/factory.go +++ b/events/sinks/factory.go @@ -21,6 +21,7 @@ import ( "k8s.io/heapster/events/core" "k8s.io/heapster/events/sinks/elasticsearch" "k8s.io/heapster/events/sinks/gcl" + "k8s.io/heapster/events/sinks/honeycomb" "k8s.io/heapster/events/sinks/influxdb" "k8s.io/heapster/events/sinks/kafka" "k8s.io/heapster/events/sinks/log" @@ -46,6 +47,8 @@ func (this *SinkFactory) Build(uri flags.Uri) (core.EventSink, error) { return kafka.NewKafkaSink(&uri.Val) case "riemann": return riemann.CreateRiemannSink(&uri.Val) + case "honeycomb": + return honeycomb.NewHoneycombSink(&uri.Val) default: return nil, fmt.Errorf("Sink not recognized: %s", uri.Key) } diff --git a/events/sinks/honeycomb/driver.go b/events/sinks/honeycomb/driver.go new file mode 100644 index 0000000000..b86c3a5c00 --- /dev/null +++ b/events/sinks/honeycomb/driver.go @@ -0,0 +1,95 @@ +// Copyright 2017 Google Inc. All Rights Reserved. +// +// Licensed 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 honeycomb + +import ( + "net/url" + "sync" + + "github.com/golang/glog" + kube_api "k8s.io/client-go/pkg/api/v1" + honeycomb_common "k8s.io/heapster/common/honeycomb" + event_core "k8s.io/heapster/events/core" +) + +type honeycombSink struct { + client honeycomb_common.Client + sync.Mutex +} + +type exportedData struct { + Namespace string `json:"namespace"` + Kind string `json:"kind"` + Name string `json:"name"` + SubObject string `json:"subobject"` + SourceComponent string `json:"source.component"` + SourceHost string `json:"source.host"` + Count int32 `json:"count"` + Type string `json:"type"` + Reason string `json:"reason"` + Message string `json:"message"` +} + +func getExportedData(e *kube_api.Event) *exportedData { + return &exportedData{ + Namespace: e.InvolvedObject.Namespace, + Kind: e.InvolvedObject.Kind, + Name: e.InvolvedObject.Name, + SubObject: e.InvolvedObject.FieldPath, + SourceComponent: e.Source.Component, + SourceHost: e.Source.Host, + Count: e.Count, + Reason: e.Reason, + Type: e.Type, + Message: e.Message, + } +} + +func (sink *honeycombSink) ExportEvents(eventBatch *event_core.EventBatch) { + sink.Lock() + defer sink.Unlock() + exportedBatch := make(honeycomb_common.Batch, len(eventBatch.Events)) + for i, event := range eventBatch.Events { + data := getExportedData(event) + exportedBatch[i] = &honeycomb_common.BatchPoint{ + Data: data, + Timestamp: event.LastTimestamp.UTC(), + } + } + err := sink.client.SendBatch(exportedBatch) + if err != nil { + glog.Warningf("Failed to send event: %v", err) + return + } +} + +func (sink *honeycombSink) Stop() {} + +func (sink *honeycombSink) Name() string { + return "Honeycomb Sink" +} + +func NewHoneycombSink(uri *url.URL) (event_core.EventSink, error) { + client, err := honeycomb_common.NewClient(uri) + if err != nil { + return nil, err + } + sink := &honeycombSink{ + client: client, + } + + return sink, nil + +} diff --git a/events/sinks/honeycomb/honeycomb_test.go b/events/sinks/honeycomb/honeycomb_test.go new file mode 100644 index 0000000000..8717958b38 --- /dev/null +++ b/events/sinks/honeycomb/honeycomb_test.go @@ -0,0 +1,93 @@ +// Copyright 2015 Google Inc. All Rights Reserved. +// +// Licensed 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 honeycomb + +import ( + "testing" + "time" + + "net/url" + + "github.com/stretchr/testify/assert" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + kube_api "k8s.io/client-go/pkg/api/v1" + honeycomb_common "k8s.io/heapster/common/honeycomb" + "k8s.io/heapster/events/core" +) + +type fakeHoneycombEventSink struct { + core.EventSink + fakeDbClient *honeycomb_common.FakeHoneycombClient +} + +func NewFakeSink() fakeHoneycombEventSink { + fakeClient := honeycomb_common.NewFakeHoneycombClient() + return fakeHoneycombEventSink{ + &honeycombSink{ + client: fakeClient, + }, + fakeClient, + } +} + +func TestStoreDataEmptyInput(t *testing.T) { + fakeSink := NewFakeSink() + eventBatch := core.EventBatch{} + fakeSink.ExportEvents(&eventBatch) + assert.Equal(t, 0, len(fakeSink.fakeDbClient.BatchPoints)) +} + +func TestStoreMultipleDataInput(t *testing.T) { + fakeSink := NewFakeSink() + timestamp := time.Now() + + now := time.Now() + event1 := kube_api.Event{ + Message: "event1", + Count: 100, + LastTimestamp: metav1.NewTime(now), + FirstTimestamp: metav1.NewTime(now), + } + + event2 := kube_api.Event{ + Message: "event2", + Count: 101, + LastTimestamp: metav1.NewTime(now), + FirstTimestamp: metav1.NewTime(now), + } + + data := core.EventBatch{ + Timestamp: timestamp, + Events: []*kube_api.Event{ + &event1, + &event2, + }, + } + + fakeSink.ExportEvents(&data) + assert.Equal(t, 2, len(fakeSink.fakeDbClient.BatchPoints)) +} + +func TestCreateHoneycombSink(t *testing.T) { + stubHoneycombURL, err := url.Parse("?dataset=testdataset&writekey=testwritekey") + assert.NoError(t, err) + + //create honeycomb sink + sink, err := NewHoneycombSink(stubHoneycombURL) + assert.NoError(t, err) + + //check sink name + assert.Equal(t, sink.Name(), "Honeycomb Sink") +} diff --git a/metrics/sinks/factory.go b/metrics/sinks/factory.go index bbcb7ba006..aac4205751 100644 --- a/metrics/sinks/factory.go +++ b/metrics/sinks/factory.go @@ -25,6 +25,7 @@ import ( "k8s.io/heapster/metrics/sinks/gcm" "k8s.io/heapster/metrics/sinks/graphite" "k8s.io/heapster/metrics/sinks/hawkular" + "k8s.io/heapster/metrics/sinks/honeycomb" "k8s.io/heapster/metrics/sinks/influxdb" "k8s.io/heapster/metrics/sinks/kafka" "k8s.io/heapster/metrics/sinks/librato" @@ -69,6 +70,8 @@ func (this *SinkFactory) Build(uri flags.Uri) (core.DataSink, error) { return wavefront.NewWavefrontSink(&uri.Val) case "riemann": return riemann.CreateRiemannSink(&uri.Val) + case "honeycomb": + return honeycomb.NewHoneycombSink(&uri.Val) default: return nil, fmt.Errorf("Sink not recognized: %s", uri.Key) } diff --git a/metrics/sinks/honeycomb/driver.go b/metrics/sinks/honeycomb/driver.go new file mode 100644 index 0000000000..12c5b0fdd6 --- /dev/null +++ b/metrics/sinks/honeycomb/driver.go @@ -0,0 +1,95 @@ +// Copyright 2017 Google Inc. All Rights Reserved. +// +// Licensed 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 honeycomb + +import ( + "net/url" + "sync" + + "github.com/golang/glog" + honeycomb_common "k8s.io/heapster/common/honeycomb" + "k8s.io/heapster/metrics/core" +) + +// These metrics report cumulative values over the lifetime of the process. +// Heapster also reports gauges (e.g., "cpu/usage_rate"). Cumulative metrics +// are more confusing than helpful, so let's not send them in the first place. +var blacklist = map[string]struct{}{ + "cpu/usage": {}, + "memory/major_page_faults": {}, + "memory/page_faults": {}, + "network/rx_errors": {}, + "network/rx": {}, + "network/tx_errors": {}, + "network/tx": {}, +} + +type honeycombSink struct { + client honeycomb_common.Client + sync.Mutex +} + +type Point struct { + MetricsName string + MetricsTags string +} + +func (sink *honeycombSink) ExportData(dataBatch *core.DataBatch) { + + sink.Lock() + defer sink.Unlock() + + batch := make(honeycomb_common.Batch, len(dataBatch.MetricSets)) + + i := 0 + for _, metricSet := range dataBatch.MetricSets { + data := make(map[string]interface{}) + for metricName, metricValue := range metricSet.MetricValues { + if _, ok := blacklist[metricName]; ok { + continue + } + data[metricName] = metricValue.GetValue() + } + for k, v := range metricSet.Labels { + data[k] = v + } + batch[i] = &honeycomb_common.BatchPoint{ + Data: data, + Timestamp: dataBatch.Timestamp, + } + i++ + } + err := sink.client.SendBatch(batch) + if err != nil { + glog.Warningf("Failed to send metrics batch: %v", err) + } +} + +func (sink *honeycombSink) Stop() {} +func (sink *honeycombSink) Name() string { + return "Honeycomb Sink" +} + +func NewHoneycombSink(uri *url.URL) (core.DataSink, error) { + client, err := honeycomb_common.NewClient(uri) + if err != nil { + return nil, err + } + sink := &honeycombSink{ + client: client, + } + + return sink, nil +} diff --git a/metrics/sinks/honeycomb/honeycomb_test.go b/metrics/sinks/honeycomb/honeycomb_test.go new file mode 100644 index 0000000000..09b5f5dae8 --- /dev/null +++ b/metrics/sinks/honeycomb/honeycomb_test.go @@ -0,0 +1,159 @@ +// Copyright 2017 Google Inc. All Rights Reserved. +// +// Licensed 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 honeycomb + +import ( + "net/url" + "testing" + "time" + + "github.com/stretchr/testify/assert" + honeycomb_common "k8s.io/heapster/common/honeycomb" + "k8s.io/heapster/metrics/core" +) + +type fakeHoneycombDataSink struct { + core.DataSink + fakeDbClient *honeycomb_common.FakeHoneycombClient +} + +func newRawHoneycombSink(client honeycomb_common.Client) *honeycombSink { + return &honeycombSink{ + client: client, + } +} + +func NewFakeSink() fakeHoneycombDataSink { + fakeClient := honeycomb_common.NewFakeHoneycombClient() + return fakeHoneycombDataSink{ + newRawHoneycombSink(fakeClient), + fakeClient, + } +} + +func TestStoreDataEmptyInput(t *testing.T) { + fakeSink := NewFakeSink() + dataBatch := core.DataBatch{} + fakeSink.ExportData(&dataBatch) + assert.Equal(t, 0, len(fakeSink.fakeDbClient.BatchPoints)) +} + +func TestStoreMultipleDataInput(t *testing.T) { + fakeSink := NewFakeSink() + timestamp := time.Now() + + l := make(map[string]string) + l["namespace_id"] = "123" + l["container_name"] = "/system.slice/-.mount" + l[core.LabelPodId.Key] = "aaaa-bbbb-cccc-dddd" + + l2 := make(map[string]string) + l2["namespace_id"] = "123" + l2["container_name"] = "/system.slice/dbus.service" + l2[core.LabelPodId.Key] = "aaaa-bbbb-cccc-dddd" + + l3 := make(map[string]string) + l3["namespace_id"] = "123" + l3[core.LabelPodId.Key] = "aaaa-bbbb-cccc-dddd" + + l4 := make(map[string]string) + l4["namespace_id"] = "" + l4[core.LabelPodId.Key] = "aaaa-bbbb-cccc-dddd" + + l5 := make(map[string]string) + l5["namespace_id"] = "123" + l5[core.LabelPodId.Key] = "aaaa-bbbb-cccc-dddd" + + metricSet1 := core.MetricSet{ + Labels: l, + MetricValues: map[string]core.MetricValue{ + "/system.slice/-.mount//cpu/limit": { + ValueType: core.ValueInt64, + MetricType: core.MetricCumulative, + IntValue: 123456, + }, + }, + } + + metricSet2 := core.MetricSet{ + Labels: l2, + MetricValues: map[string]core.MetricValue{ + "/system.slice/dbus.service//cpu/usage": { + ValueType: core.ValueInt64, + MetricType: core.MetricCumulative, + IntValue: 123456, + }, + }, + } + + metricSet3 := core.MetricSet{ + Labels: l3, + MetricValues: map[string]core.MetricValue{ + "test/metric/1": { + ValueType: core.ValueInt64, + MetricType: core.MetricCumulative, + IntValue: 123456, + }, + }, + } + + metricSet4 := core.MetricSet{ + Labels: l4, + MetricValues: map[string]core.MetricValue{ + "test/metric/1": { + ValueType: core.ValueInt64, + MetricType: core.MetricCumulative, + IntValue: 123456, + }, + }, + } + + metricSet5 := core.MetricSet{ + Labels: l5, + MetricValues: map[string]core.MetricValue{ + "removeme": { + ValueType: core.ValueFloat, + MetricType: core.MetricCumulative, + FloatValue: 1.23456, + }, + }, + } + + data := core.DataBatch{ + Timestamp: timestamp, + MetricSets: map[string]*core.MetricSet{ + "pod1": &metricSet1, + "pod2": &metricSet2, + "pod3": &metricSet3, + "pod4": &metricSet4, + "pod5": &metricSet5, + }, + } + + fakeSink.ExportData(&data) + assert.Equal(t, 5, len(fakeSink.fakeDbClient.BatchPoints)) +} + +func TestCreateHoneycombSink(t *testing.T) { + stubHoneycombURL, err := url.Parse("?dataset=testdataset&writekey=testwritekey") + assert.NoError(t, err) + + //create honeycomb sink + sink, err := NewHoneycombSink(stubHoneycombURL) + assert.NoError(t, err) + + //check sink name + assert.Equal(t, sink.Name(), "Honeycomb Sink") +} From 0f581893c14cb15a43a4f572dadb70293a12dd4b Mon Sep 17 00:00:00 2001 From: Eben Freeman Date: Mon, 14 Aug 2017 12:26:31 -0700 Subject: [PATCH 2/2] Update sink-owners with honeycomb info --- docs/sink-owners.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/sink-owners.md b/docs/sink-owners.md index 4649c6e5e8..1f06f08d59 100644 --- a/docs/sink-owners.md +++ b/docs/sink-owners.md @@ -37,3 +37,4 @@ List of Owners | Graphite | :heavy_check_mark: | :x: | @jsoriano / @theairkit | :new: #1341 | | Wavefront | :heavy_check_mark: | :x: | @ezeev | :ok: | | Librato | :heavy_check_mark: | :x: | @johanneswuerbach | :ok: | +| Honeycomb | :heavy_check_mark: | :heavy_check_mark: | @emfree | :new: #1762 |