Webhooks plugin: add mandrill (#1408)
* Add mandrill webhook. * Store the id of the msg as part of event. Signed-off-by: Cyril Duez <cyril@stormz.me> Signed-off-by: François de Metz <francois@stormz.me> * Decode body to get the mandrill_events. Signed-off-by: Cyril Duez <cyril@stormz.me> Signed-off-by: François de Metz <francois@stormz.me> * Handle HEAD request. Signed-off-by: Cyril Duez <cyril@stormz.me> Signed-off-by: François de Metz <francois@stormz.me> * Add the README. Signed-off-by: Cyril Duez <cyril@stormz.me> Signed-off-by: François de Metz <francois@stormz.me> * Add mandrill_webhooks to the README. Signed-off-by: Cyril Duez <cyril@stormz.me> Signed-off-by: François de Metz <francois@stormz.me> * Update changelog. Signed-off-by: Cyril Duez <cyril@stormz.me> Signed-off-by: François de Metz <francois@stormz.me> * Run gofmt. Signed-off-by: Cyril Duez <cyril@stormz.me> Signed-off-by: François de Metz <francois@stormz.me>
This commit is contained in:
parent
5dc4cce157
commit
1c2965703d
|
@ -36,6 +36,7 @@ should now look like:
|
||||||
|
|
||||||
- [#1289](https://github.com/influxdata/telegraf/pull/1289): webhooks input plugin. Thanks @francois2metz and @cduez!
|
- [#1289](https://github.com/influxdata/telegraf/pull/1289): webhooks input plugin. Thanks @francois2metz and @cduez!
|
||||||
- [#1247](https://github.com/influxdata/telegraf/pull/1247): rollbar webhook plugin.
|
- [#1247](https://github.com/influxdata/telegraf/pull/1247): rollbar webhook plugin.
|
||||||
|
- [#1408](https://github.com/influxdata/telegraf/pull/1408): mandrill webhook plugin.
|
||||||
- [#1402](https://github.com/influxdata/telegraf/pull/1402): docker-machine/boot2docker no longer required for unit tests.
|
- [#1402](https://github.com/influxdata/telegraf/pull/1402): docker-machine/boot2docker no longer required for unit tests.
|
||||||
- [#1350](https://github.com/influxdata/telegraf/pull/1350): cgroup input plugin.
|
- [#1350](https://github.com/influxdata/telegraf/pull/1350): cgroup input plugin.
|
||||||
- [#1369](https://github.com/influxdata/telegraf/pull/1369): Add input plugin for consuming metrics from NSQD.
|
- [#1369](https://github.com/influxdata/telegraf/pull/1369): Add input plugin for consuming metrics from NSQD.
|
||||||
|
|
|
@ -219,6 +219,7 @@ Telegraf can also collect metrics via the following service plugins:
|
||||||
* [nats_consumer](https://github.com/influxdata/telegraf/tree/master/plugins/inputs/nats_consumer)
|
* [nats_consumer](https://github.com/influxdata/telegraf/tree/master/plugins/inputs/nats_consumer)
|
||||||
* [webhooks](https://github.com/influxdata/telegraf/tree/master/plugins/inputs/webhooks)
|
* [webhooks](https://github.com/influxdata/telegraf/tree/master/plugins/inputs/webhooks)
|
||||||
* [github](https://github.com/influxdata/telegraf/tree/master/plugins/inputs/webhooks/github)
|
* [github](https://github.com/influxdata/telegraf/tree/master/plugins/inputs/webhooks/github)
|
||||||
|
* [mandrill](https://github.com/influxdata/telegraf/tree/master/plugins/inputs/webhooks/mandrill)
|
||||||
* [rollbar](https://github.com/influxdata/telegraf/tree/master/plugins/inputs/webhooks/rollbar)
|
* [rollbar](https://github.com/influxdata/telegraf/tree/master/plugins/inputs/webhooks/rollbar)
|
||||||
* [nsq_consumer](https://github.com/influxdata/telegraf/tree/master/plugins/inputs/nsq_consumer)
|
* [nsq_consumer](https://github.com/influxdata/telegraf/tree/master/plugins/inputs/nsq_consumer)
|
||||||
|
|
||||||
|
|
|
@ -16,6 +16,7 @@ $ sudo service telegraf start
|
||||||
## Available webhooks
|
## Available webhooks
|
||||||
|
|
||||||
- [Github](github/)
|
- [Github](github/)
|
||||||
|
- [Mandrill](mandrill/)
|
||||||
- [Rollbar](rollbar/)
|
- [Rollbar](rollbar/)
|
||||||
|
|
||||||
## Adding new webhooks plugin
|
## Adding new webhooks plugin
|
||||||
|
|
|
@ -0,0 +1,15 @@
|
||||||
|
# mandrill webhook
|
||||||
|
|
||||||
|
You should configure your Mandrill's Webhooks to point at the `webhooks` service. To do this go to `mandrillapp.com/` and click `Settings > Webhooks`. In the resulting page, click on `Add a Webhook`, select all events, and set the `URL` to `http://<my_ip>:1619/mandrill`, and click on `Create Webhook`.
|
||||||
|
|
||||||
|
## Events
|
||||||
|
|
||||||
|
See the [webhook doc](https://mandrill.zendesk.com/hc/en-us/articles/205583307-Message-Event-Webhook-format).
|
||||||
|
|
||||||
|
All events for logs the original timestamp, the event name and the unique identifier of the message that generated the event.
|
||||||
|
|
||||||
|
**Tags:**
|
||||||
|
* 'event' = `event.event` string
|
||||||
|
|
||||||
|
**Fields:**
|
||||||
|
* 'id' = `event._id` string
|
|
@ -0,0 +1,56 @@
|
||||||
|
package mandrill
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"io/ioutil"
|
||||||
|
"log"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/gorilla/mux"
|
||||||
|
"github.com/influxdata/telegraf"
|
||||||
|
)
|
||||||
|
|
||||||
|
type MandrillWebhook struct {
|
||||||
|
Path string
|
||||||
|
acc telegraf.Accumulator
|
||||||
|
}
|
||||||
|
|
||||||
|
func (md *MandrillWebhook) Register(router *mux.Router, acc telegraf.Accumulator) {
|
||||||
|
router.HandleFunc(md.Path, md.returnOK).Methods("HEAD")
|
||||||
|
router.HandleFunc(md.Path, md.eventHandler).Methods("POST")
|
||||||
|
|
||||||
|
log.Printf("Started the webhooks_mandrill on %s\n", md.Path)
|
||||||
|
md.acc = acc
|
||||||
|
}
|
||||||
|
|
||||||
|
func (md *MandrillWebhook) returnOK(w http.ResponseWriter, r *http.Request) {
|
||||||
|
w.WriteHeader(http.StatusOK)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (md *MandrillWebhook) eventHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
|
defer r.Body.Close()
|
||||||
|
body, err := ioutil.ReadAll(r.Body)
|
||||||
|
if err != nil {
|
||||||
|
w.WriteHeader(http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
data, err := url.ParseQuery(string(body))
|
||||||
|
if err != nil {
|
||||||
|
w.WriteHeader(http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var events []MandrillEvent
|
||||||
|
err = json.Unmarshal([]byte(data.Get("mandrill_events")), &events)
|
||||||
|
if err != nil {
|
||||||
|
w.WriteHeader(http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, event := range events {
|
||||||
|
md.acc.AddFields("mandrill_webhooks", event.Fields(), event.Tags(), time.Unix(event.TimeStamp, 0))
|
||||||
|
}
|
||||||
|
|
||||||
|
w.WriteHeader(http.StatusOK)
|
||||||
|
}
|
|
@ -0,0 +1,24 @@
|
||||||
|
package mandrill
|
||||||
|
|
||||||
|
type Event interface {
|
||||||
|
Tags() map[string]string
|
||||||
|
Fields() map[string]interface{}
|
||||||
|
}
|
||||||
|
|
||||||
|
type MandrillEvent struct {
|
||||||
|
EventName string `json:"event"`
|
||||||
|
TimeStamp int64 `json:"ts"`
|
||||||
|
Id string `json:"_id"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (me *MandrillEvent) Tags() map[string]string {
|
||||||
|
return map[string]string{
|
||||||
|
"event": me.EventName,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (me *MandrillEvent) Fields() map[string]interface{} {
|
||||||
|
return map[string]interface{}{
|
||||||
|
"id": me.Id,
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,58 @@
|
||||||
|
package mandrill
|
||||||
|
|
||||||
|
func SendEventJSON() string {
|
||||||
|
return `
|
||||||
|
{
|
||||||
|
"event": "send",
|
||||||
|
"msg": {
|
||||||
|
"ts": 1365109999,
|
||||||
|
"subject": "This an example webhook message",
|
||||||
|
"email": "example.webhook@mandrillapp.com",
|
||||||
|
"sender": "example.sender@mandrillapp.com",
|
||||||
|
"tags": [
|
||||||
|
"webhook-example"
|
||||||
|
],
|
||||||
|
"opens": [
|
||||||
|
|
||||||
|
],
|
||||||
|
"clicks": [
|
||||||
|
|
||||||
|
],
|
||||||
|
"state": "sent",
|
||||||
|
"metadata": {
|
||||||
|
"user_id": 111
|
||||||
|
},
|
||||||
|
"_id": "exampleaaaaaaaaaaaaaaaaaaaaaaaaa",
|
||||||
|
"_version": "exampleaaaaaaaaaaaaaaa"
|
||||||
|
},
|
||||||
|
"_id": "id1",
|
||||||
|
"ts": 1384954004
|
||||||
|
}`
|
||||||
|
}
|
||||||
|
|
||||||
|
func HardBounceEventJSON() string {
|
||||||
|
return `
|
||||||
|
{
|
||||||
|
"event": "hard_bounce",
|
||||||
|
"msg": {
|
||||||
|
"ts": 1365109999,
|
||||||
|
"subject": "This an example webhook message",
|
||||||
|
"email": "example.webhook@mandrillapp.com",
|
||||||
|
"sender": "example.sender@mandrillapp.com",
|
||||||
|
"tags": [
|
||||||
|
"webhook-example"
|
||||||
|
],
|
||||||
|
"state": "bounced",
|
||||||
|
"metadata": {
|
||||||
|
"user_id": 111
|
||||||
|
},
|
||||||
|
"_id": "exampleaaaaaaaaaaaaaaaaaaaaaaaaa2",
|
||||||
|
"_version": "exampleaaaaaaaaaaaaaaa",
|
||||||
|
"bounce_description": "bad_mailbox",
|
||||||
|
"bgtools_code": 10,
|
||||||
|
"diag": "smtp;550 5.1.1 The email account that you tried to reach does not exist. Please try double-checking the recipient's email address for typos or unnecessary spaces."
|
||||||
|
},
|
||||||
|
"_id": "id2",
|
||||||
|
"ts": 1384954004
|
||||||
|
}`
|
||||||
|
}
|
|
@ -0,0 +1,85 @@
|
||||||
|
package mandrill
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/influxdata/telegraf/testutil"
|
||||||
|
"net/http"
|
||||||
|
"net/http/httptest"
|
||||||
|
"net/url"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func postWebhooks(md *MandrillWebhook, eventBody string) *httptest.ResponseRecorder {
|
||||||
|
body := url.Values{}
|
||||||
|
body.Set("mandrill_events", eventBody)
|
||||||
|
req, _ := http.NewRequest("POST", "/mandrill", strings.NewReader(body.Encode()))
|
||||||
|
w := httptest.NewRecorder()
|
||||||
|
|
||||||
|
md.eventHandler(w, req)
|
||||||
|
|
||||||
|
return w
|
||||||
|
}
|
||||||
|
|
||||||
|
func headRequest(md *MandrillWebhook) *httptest.ResponseRecorder {
|
||||||
|
req, _ := http.NewRequest("HEAD", "/mandrill", strings.NewReader(""))
|
||||||
|
w := httptest.NewRecorder()
|
||||||
|
|
||||||
|
md.returnOK(w, req)
|
||||||
|
|
||||||
|
return w
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestHead(t *testing.T) {
|
||||||
|
md := &MandrillWebhook{Path: "/mandrill"}
|
||||||
|
resp := headRequest(md)
|
||||||
|
if resp.Code != http.StatusOK {
|
||||||
|
t.Errorf("HEAD returned HTTP status code %v.\nExpected %v", resp.Code, http.StatusOK)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSendEvent(t *testing.T) {
|
||||||
|
var acc testutil.Accumulator
|
||||||
|
md := &MandrillWebhook{Path: "/mandrill", acc: &acc}
|
||||||
|
resp := postWebhooks(md, "["+SendEventJSON()+"]")
|
||||||
|
if resp.Code != http.StatusOK {
|
||||||
|
t.Errorf("POST send returned HTTP status code %v.\nExpected %v", resp.Code, http.StatusOK)
|
||||||
|
}
|
||||||
|
|
||||||
|
fields := map[string]interface{}{
|
||||||
|
"id": "id1",
|
||||||
|
}
|
||||||
|
|
||||||
|
tags := map[string]string{
|
||||||
|
"event": "send",
|
||||||
|
}
|
||||||
|
|
||||||
|
acc.AssertContainsTaggedFields(t, "mandrill_webhooks", fields, tags)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMultipleEvents(t *testing.T) {
|
||||||
|
var acc testutil.Accumulator
|
||||||
|
md := &MandrillWebhook{Path: "/mandrill", acc: &acc}
|
||||||
|
resp := postWebhooks(md, "["+SendEventJSON()+","+HardBounceEventJSON()+"]")
|
||||||
|
if resp.Code != http.StatusOK {
|
||||||
|
t.Errorf("POST send returned HTTP status code %v.\nExpected %v", resp.Code, http.StatusOK)
|
||||||
|
}
|
||||||
|
|
||||||
|
fields := map[string]interface{}{
|
||||||
|
"id": "id1",
|
||||||
|
}
|
||||||
|
|
||||||
|
tags := map[string]string{
|
||||||
|
"event": "send",
|
||||||
|
}
|
||||||
|
|
||||||
|
acc.AssertContainsTaggedFields(t, "mandrill_webhooks", fields, tags)
|
||||||
|
|
||||||
|
fields = map[string]interface{}{
|
||||||
|
"id": "id2",
|
||||||
|
}
|
||||||
|
|
||||||
|
tags = map[string]string{
|
||||||
|
"event": "hard_bounce",
|
||||||
|
}
|
||||||
|
acc.AssertContainsTaggedFields(t, "mandrill_webhooks", fields, tags)
|
||||||
|
}
|
|
@ -11,6 +11,7 @@ import (
|
||||||
"github.com/influxdata/telegraf/plugins/inputs"
|
"github.com/influxdata/telegraf/plugins/inputs"
|
||||||
|
|
||||||
"github.com/influxdata/telegraf/plugins/inputs/webhooks/github"
|
"github.com/influxdata/telegraf/plugins/inputs/webhooks/github"
|
||||||
|
"github.com/influxdata/telegraf/plugins/inputs/webhooks/mandrill"
|
||||||
"github.com/influxdata/telegraf/plugins/inputs/webhooks/rollbar"
|
"github.com/influxdata/telegraf/plugins/inputs/webhooks/rollbar"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -26,6 +27,7 @@ type Webhooks struct {
|
||||||
ServiceAddress string
|
ServiceAddress string
|
||||||
|
|
||||||
Github *github.GithubWebhook
|
Github *github.GithubWebhook
|
||||||
|
Mandrill *mandrill.MandrillWebhook
|
||||||
Rollbar *rollbar.RollbarWebhook
|
Rollbar *rollbar.RollbarWebhook
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -41,6 +43,9 @@ func (wb *Webhooks) SampleConfig() string {
|
||||||
[inputs.webhooks.github]
|
[inputs.webhooks.github]
|
||||||
path = "/github"
|
path = "/github"
|
||||||
|
|
||||||
|
[inputs.webhooks.mandrill]
|
||||||
|
path = "/mandrill"
|
||||||
|
|
||||||
[inputs.webhooks.rollbar]
|
[inputs.webhooks.rollbar]
|
||||||
path = "/rollbar"
|
path = "/rollbar"
|
||||||
`
|
`
|
||||||
|
|
Loading…
Reference in New Issue