Add new webhooks plugin that superseed github and rollbar plugins.

closes #1289

Signed-off-by: François de Metz <francois@stormz.me>
Signed-off-by: Cyril Duez <cyril@stormz.me>

Rename internals struct.

Signed-off-by: François de Metz <francois@stormz.me>
Signed-off-by: Cyril Duez <cyril@stormz.me>

Update changelog.

Signed-off-by: François de Metz <francois@stormz.me>
Signed-off-by: Cyril Duez <cyril@stormz.me>

Update READMEs and CHANGELOG.

Signed-off-by: François de Metz <francois@stormz.me>
Signed-off-by: Cyril Duez <cyril@stormz.me>

Update SampleConfig.

Update the config format.

Update telegraf config.

Update the webhooks README.

Update changelog.

Update the changelog with an upgrade path.

Update default ports.

Fix indent.

Check for nil value on AvailableWebhooks.

Check for CanInterface.
This commit is contained in:
François de Metz
2016-05-27 17:27:54 +02:00
committed by Cameron Sparr
parent e3448153e1
commit e603825e37
18 changed files with 302 additions and 235 deletions

View File

@@ -0,0 +1,27 @@
# Webhooks
This is a Telegraf service plugin that start an http server and register multiple webhook listeners.
```sh
$ telegraf -sample-config -input-filter webhooks -output-filter influxdb > config.conf.new
```
Change the config file to point to the InfluxDB server you are using and adjust the settings to match your environment. Once that is complete:
```sh
$ cp config.conf.new /etc/telegraf/telegraf.conf
$ sudo service telegraf start
```
## Available webhooks
- [Github](github/)
- [Rollbar](rollbar/)
## Adding new webhooks plugin
1. Add your webhook plugin inside the `webhooks` folder
1. Your plugin must implement the `Webhook` interface
1. Import your plugin in the `webhooks.go` file and add it to the `Webhooks` struct
Both [Github](github/) and [Rollbar](rollbar/) are good example to follow.

View File

@@ -0,0 +1,360 @@
# github webhooks
You should configure your Organization's Webhooks to point at the `webhooks` service. To do this go to `github.com/{my_organization}` and click `Settings > Webhooks > Add webhook`. In the resulting menu set `Payload URL` to `http://<my_ip>:1619/github`, `Content type` to `application/json` and under the section `Which events would you like to trigger this webhook?` select 'Send me <b>everything</b>'. By default all of the events will write to the `github_webhooks` measurement, this is configurable by setting the `measurement_name` in the config file.
## Events
The titles of the following sections are links to the full payloads and details for each event. The body contains what information from the event is persisted. The format is as follows:
```
# TAGS
* 'tagKey' = `tagValue` type
# FIELDS
* 'fieldKey' = `fieldValue` type
```
The tag values and field values show the place on the incoming JSON object where the data is sourced from.
#### [`commit_comment` event](https://developer.github.com/v3/activity/events/types/#commitcommentevent)
**Tags:**
* 'event' = `headers[X-Github-Event]` string
* 'repository' = `event.repository.full_name` string
* 'private' = `event.repository.private` bool
* 'user' = `event.sender.login` string
* 'admin' = `event.sender.site_admin` bool
**Fields:**
* 'stars' = `event.repository.stargazers_count` int
* 'forks' = `event.repository.forks_count` int
* 'issues' = `event.repository.open_issues_count` int
* 'commit' = `event.comment.commit_id` string
* 'comment' = `event.comment.body` string
#### [`create` event](https://developer.github.com/v3/activity/events/types/#createevent)
**Tags:**
* 'event' = `headers[X-Github-Event]` string
* 'repository' = `event.repository.full_name` string
* 'private' = `event.repository.private` bool
* 'user' = `event.sender.login` string
* 'admin' = `event.sender.site_admin` bool
**Fields:**
* 'stars' = `event.repository.stargazers_count` int
* 'forks' = `event.repository.forks_count` int
* 'issues' = `event.repository.open_issues_count` int
* 'ref' = `event.ref` string
* 'issues' = `event.ref_type` string
#### [`delete` event](https://developer.github.com/v3/activity/events/types/#deleteevent)
**Tags:**
* 'event' = `headers[X-Github-Event]` string
* 'repository' = `event.repository.full_name` string
* 'private' = `event.repository.private` bool
* 'user' = `event.sender.login` string
* 'admin' = `event.sender.site_admin` bool
**Fields:**
* 'stars' = `event.repository.stargazers_count` int
* 'forks' = `event.repository.forks_count` int
* 'issues' = `event.repository.open_issues_count` int
* 'ref' = `event.ref` string
* 'issues' = `event.ref_type` string
#### [`deployment` event](https://developer.github.com/v3/activity/events/types/#deploymentevent)
**Tags:**
* 'event' = `headers[X-Github-Event]` string
* 'repository' = `event.repository.full_name` string
* 'private' = `event.repository.private` bool
* 'user' = `event.sender.login` string
* 'admin' = `event.sender.site_admin` bool
**Fields:**
* 'stars' = `event.repository.stargazers_count` int
* 'forks' = `event.repository.forks_count` int
* 'issues' = `event.repository.open_issues_count` int
* 'commit' = `event.deployment.sha` string
* 'task' = `event.deployment.task` string
* 'environment' = `event.deployment.evnironment` string
* 'description' = `event.deployment.description` string
#### [`deployment_status` event](https://developer.github.com/v3/activity/events/types/#deploymentstatusevent)
**Tags:**
* 'event' = `headers[X-Github-Event]` string
* 'repository' = `event.repository.full_name` string
* 'private' = `event.repository.private` bool
* 'user' = `event.sender.login` string
* 'admin' = `event.sender.site_admin` bool
**Fields:**
* 'stars' = `event.repository.stargazers_count` int
* 'forks' = `event.repository.forks_count` int
* 'issues' = `event.repository.open_issues_count` int
* 'commit' = `event.deployment.sha` string
* 'task' = `event.deployment.task` string
* 'environment' = `event.deployment.evnironment` string
* 'description' = `event.deployment.description` string
* 'depState' = `event.deployment_status.state` string
* 'depDescription' = `event.deployment_status.description` string
#### [`fork` event](https://developer.github.com/v3/activity/events/types/#forkevent)
**Tags:**
* 'event' = `headers[X-Github-Event]` string
* 'repository' = `event.repository.full_name` string
* 'private' = `event.repository.private` bool
* 'user' = `event.sender.login` string
* 'admin' = `event.sender.site_admin` bool
**Fields:**
* 'stars' = `event.repository.stargazers_count` int
* 'forks' = `event.repository.forks_count` int
* 'issues' = `event.repository.open_issues_count` int
* 'forkee' = `event.forkee.repository` string
#### [`gollum` event](https://developer.github.com/v3/activity/events/types/#gollumevent)
**Tags:**
* 'event' = `headers[X-Github-Event]` string
* 'repository' = `event.repository.full_name` string
* 'private' = `event.repository.private` bool
* 'user' = `event.sender.login` string
* 'admin' = `event.sender.site_admin` bool
**Fields:**
* 'stars' = `event.repository.stargazers_count` int
* 'forks' = `event.repository.forks_count` int
* 'issues' = `event.repository.open_issues_count` int
#### [`issue_comment` event](https://developer.github.com/v3/activity/events/types/#issuecommentevent)
**Tags:**
* 'event' = `headers[X-Github-Event]` string
* 'repository' = `event.repository.full_name` string
* 'private' = `event.repository.private` bool
* 'user' = `event.sender.login` string
* 'admin' = `event.sender.site_admin` bool
* 'issue' = `event.issue.number` int
**Fields:**
* 'stars' = `event.repository.stargazers_count` int
* 'forks' = `event.repository.forks_count` int
* 'issues' = `event.repository.open_issues_count` int
* 'title' = `event.issue.title` string
* 'comments' = `event.issue.comments` int
* 'body' = `event.comment.body` string
#### [`issues` event](https://developer.github.com/v3/activity/events/types/#issuesevent)
**Tags:**
* 'event' = `headers[X-Github-Event]` string
* 'repository' = `event.repository.full_name` string
* 'private' = `event.repository.private` bool
* 'user' = `event.sender.login` string
* 'admin' = `event.sender.site_admin` bool
* 'issue' = `event.issue.number` int
* 'action' = `event.action` string
**Fields:**
* 'stars' = `event.repository.stargazers_count` int
* 'forks' = `event.repository.forks_count` int
* 'issues' = `event.repository.open_issues_count` int
* 'title' = `event.issue.title` string
* 'comments' = `event.issue.comments` int
#### [`member` event](https://developer.github.com/v3/activity/events/types/#memberevent)
**Tags:**
* 'event' = `headers[X-Github-Event]` string
* 'repository' = `event.repository.full_name` string
* 'private' = `event.repository.private` bool
* 'user' = `event.sender.login` string
* 'admin' = `event.sender.site_admin` bool
**Fields:**
* 'stars' = `event.repository.stargazers_count` int
* 'forks' = `event.repository.forks_count` int
* 'issues' = `event.repository.open_issues_count` int
* 'newMember' = `event.sender.login` string
* 'newMemberStatus' = `event.sender.site_admin` bool
#### [`membership` event](https://developer.github.com/v3/activity/events/types/#membershipevent)
**Tags:**
* 'event' = `headers[X-Github-Event]` string
* 'user' = `event.sender.login` string
* 'admin' = `event.sender.site_admin` bool
* 'action' = `event.action` string
**Fields:**
* 'newMember' = `event.sender.login` string
* 'newMemberStatus' = `event.sender.site_admin` bool
#### [`page_build` event](https://developer.github.com/v3/activity/events/types/#pagebuildevent)
**Tags:**
* 'event' = `headers[X-Github-Event]` string
* 'repository' = `event.repository.full_name` string
* 'private' = `event.repository.private` bool
* 'user' = `event.sender.login` string
* 'admin' = `event.sender.site_admin` bool
**Fields:**
* 'stars' = `event.repository.stargazers_count` int
* 'forks' = `event.repository.forks_count` int
* 'issues' = `event.repository.open_issues_count` int
#### [`public` event](https://developer.github.com/v3/activity/events/types/#publicevent)
**Tags:**
* 'event' = `headers[X-Github-Event]` string
* 'repository' = `event.repository.full_name` string
* 'private' = `event.repository.private` bool
* 'user' = `event.sender.login` string
* 'admin' = `event.sender.site_admin` bool
**Fields:**
* 'stars' = `event.repository.stargazers_count` int
* 'forks' = `event.repository.forks_count` int
* 'issues' = `event.repository.open_issues_count` int
#### [`pull_request_review_comment` event](https://developer.github.com/v3/activity/events/types/#pullrequestreviewcommentevent)
**Tags:**
* 'event' = `headers[X-Github-Event]` string
* 'action' = `event.action` string
* 'repository' = `event.repository.full_name` string
* 'private' = `event.repository.private` bool
* 'user' = `event.sender.login` string
* 'admin' = `event.sender.site_admin` bool
* 'prNumber' = `event.pull_request.number` int
**Fields:**
* 'stars' = `event.repository.stargazers_count` int
* 'forks' = `event.repository.forks_count` int
* 'issues' = `event.repository.open_issues_count` int
* 'state' = `event.pull_request.state` string
* 'title' = `event.pull_request.title` string
* 'comments' = `event.pull_request.comments` int
* 'commits' = `event.pull_request.commits` int
* 'additions' = `event.pull_request.additions` int
* 'deletions' = `event.pull_request.deletions` int
* 'changedFiles' = `event.pull_request.changed_files` int
* 'commentFile' = `event.comment.file` string
* 'comment' = `event.comment.body` string
#### [`pull_request` event](https://developer.github.com/v3/activity/events/types/#pullrequestevent)
**Tags:**
* 'event' = `headers[X-Github-Event]` string
* 'action' = `event.action` string
* 'repository' = `event.repository.full_name` string
* 'private' = `event.repository.private` bool
* 'user' = `event.sender.login` string
* 'admin' = `event.sender.site_admin` bool
* 'prNumber' = `event.pull_request.number` int
**Fields:**
* 'stars' = `event.repository.stargazers_count` int
* 'forks' = `event.repository.forks_count` int
* 'issues' = `event.repository.open_issues_count` int
* 'state' = `event.pull_request.state` string
* 'title' = `event.pull_request.title` string
* 'comments' = `event.pull_request.comments` int
* 'commits' = `event.pull_request.commits` int
* 'additions' = `event.pull_request.additions` int
* 'deletions' = `event.pull_request.deletions` int
* 'changedFiles' = `event.pull_request.changed_files` int
#### [`push` event](https://developer.github.com/v3/activity/events/types/#pushevent)
**Tags:**
* 'event' = `headers[X-Github-Event]` string
* 'repository' = `event.repository.full_name` string
* 'private' = `event.repository.private` bool
* 'user' = `event.sender.login` string
* 'admin' = `event.sender.site_admin` bool
**Fields:**
* 'stars' = `event.repository.stargazers_count` int
* 'forks' = `event.repository.forks_count` int
* 'issues' = `event.repository.open_issues_count` int
* 'ref' = `event.ref` string
* 'before' = `event.before` string
* 'after' = `event.after` string
#### [`repository` event](https://developer.github.com/v3/activity/events/types/#repositoryevent)
**Tags:**
* 'event' = `headers[X-Github-Event]` string
* 'repository' = `event.repository.full_name` string
* 'private' = `event.repository.private` bool
* 'user' = `event.sender.login` string
* 'admin' = `event.sender.site_admin` bool
**Fields:**
* 'stars' = `event.repository.stargazers_count` int
* 'forks' = `event.repository.forks_count` int
* 'issues' = `event.repository.open_issues_count` int
#### [`release` event](https://developer.github.com/v3/activity/events/types/#releaseevent)
**Tags:**
* 'event' = `headers[X-Github-Event]` string
* 'repository' = `event.repository.full_name` string
* 'private' = `event.repository.private` bool
* 'user' = `event.sender.login` string
* 'admin' = `event.sender.site_admin` bool
**Fields:**
* 'stars' = `event.repository.stargazers_count` int
* 'forks' = `event.repository.forks_count` int
* 'issues' = `event.repository.open_issues_count` int
* 'tagName' = `event.release.tag_name` string
#### [`status` event](https://developer.github.com/v3/activity/events/types/#statusevent)
**Tags:**
* 'event' = `headers[X-Github-Event]` string
* 'repository' = `event.repository.full_name` string
* 'private' = `event.repository.private` bool
* 'user' = `event.sender.login` string
* 'admin' = `event.sender.site_admin` bool
**Fields:**
* 'stars' = `event.repository.stargazers_count` int
* 'forks' = `event.repository.forks_count` int
* 'issues' = `event.repository.open_issues_count` int
* 'commit' = `event.sha` string
* 'state' = `event.state` string
#### [`team_add` event](https://developer.github.com/v3/activity/events/types/#teamaddevent)
**Tags:**
* 'event' = `headers[X-Github-Event]` string
* 'repository' = `event.repository.full_name` string
* 'private' = `event.repository.private` bool
* 'user' = `event.sender.login` string
* 'admin' = `event.sender.site_admin` bool
**Fields:**
* 'stars' = `event.repository.stargazers_count` int
* 'forks' = `event.repository.forks_count` int
* 'issues' = `event.repository.open_issues_count` int
* 'teamName' = `event.team.name` string
#### [`watch` event](https://developer.github.com/v3/activity/events/types/#watchevent)
**Tags:**
* 'event' = `headers[X-Github-Event]` string
* 'repository' = `event.repository.full_name` string
* 'private' = `event.repository.private` bool
* 'user' = `event.sender.login` string
* 'admin' = `event.sender.site_admin` bool
**Fields:**
* 'stars' = `event.repository.stargazers_count` int
* 'forks' = `event.repository.forks_count` int
* 'issues' = `event.repository.open_issues_count` int

View File

@@ -0,0 +1,107 @@
package github
import (
"encoding/json"
"io/ioutil"
"log"
"net/http"
"github.com/gorilla/mux"
"github.com/influxdata/telegraf"
)
type GithubWebhook struct {
Path string
acc telegraf.Accumulator
}
func (gh *GithubWebhook) Register(router *mux.Router, acc telegraf.Accumulator) {
router.HandleFunc(gh.Path, gh.eventHandler).Methods("POST")
log.Printf("Started the webhooks_github on %s\n", gh.Path)
gh.acc = acc
}
func (gh *GithubWebhook) eventHandler(w http.ResponseWriter, r *http.Request) {
defer r.Body.Close()
eventType := r.Header["X-Github-Event"][0]
data, err := ioutil.ReadAll(r.Body)
if err != nil {
w.WriteHeader(http.StatusBadRequest)
return
}
e, err := NewEvent(data, eventType)
if err != nil {
w.WriteHeader(http.StatusBadRequest)
return
}
p := e.NewMetric()
gh.acc.AddFields("github_webhooks", p.Fields(), p.Tags(), p.Time())
w.WriteHeader(http.StatusOK)
}
func generateEvent(data []byte, event Event) (Event, error) {
err := json.Unmarshal(data, event)
if err != nil {
return nil, err
}
return event, nil
}
type newEventError struct {
s string
}
func (e *newEventError) Error() string {
return e.s
}
func NewEvent(data []byte, name string) (Event, error) {
log.Printf("New %v event received", name)
switch name {
case "commit_comment":
return generateEvent(data, &CommitCommentEvent{})
case "create":
return generateEvent(data, &CreateEvent{})
case "delete":
return generateEvent(data, &DeleteEvent{})
case "deployment":
return generateEvent(data, &DeploymentEvent{})
case "deployment_status":
return generateEvent(data, &DeploymentStatusEvent{})
case "fork":
return generateEvent(data, &ForkEvent{})
case "gollum":
return generateEvent(data, &GollumEvent{})
case "issue_comment":
return generateEvent(data, &IssueCommentEvent{})
case "issues":
return generateEvent(data, &IssuesEvent{})
case "member":
return generateEvent(data, &MemberEvent{})
case "membership":
return generateEvent(data, &MembershipEvent{})
case "page_build":
return generateEvent(data, &PageBuildEvent{})
case "public":
return generateEvent(data, &PublicEvent{})
case "pull_request":
return generateEvent(data, &PullRequestEvent{})
case "pull_request_review_comment":
return generateEvent(data, &PullRequestReviewCommentEvent{})
case "push":
return generateEvent(data, &PushEvent{})
case "release":
return generateEvent(data, &ReleaseEvent{})
case "repository":
return generateEvent(data, &RepositoryEvent{})
case "status":
return generateEvent(data, &StatusEvent{})
case "team_add":
return generateEvent(data, &TeamAddEvent{})
case "watch":
return generateEvent(data, &WatchEvent{})
}
return nil, &newEventError{"Not a recognized event type"}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,711 @@
package github
import (
"fmt"
"log"
"time"
"github.com/influxdata/telegraf"
)
const meas = "github_webhooks"
type Event interface {
NewMetric() telegraf.Metric
}
type Repository struct {
Repository string `json:"full_name"`
Private bool `json:"private"`
Stars int `json:"stargazers_count"`
Forks int `json:"forks_count"`
Issues int `json:"open_issues_count"`
}
type Sender struct {
User string `json:"login"`
Admin bool `json:"site_admin"`
}
type CommitComment struct {
Commit string `json:"commit_id"`
Body string `json:"body"`
}
type Deployment struct {
Commit string `json:"sha"`
Task string `json:"task"`
Environment string `json:"environment"`
Description string `json:"description"`
}
type Page struct {
Name string `json:"page_name"`
Title string `json:"title"`
Action string `json:"action"`
}
type Issue struct {
Number int `json:"number"`
Title string `json:"title"`
Comments int `json:"comments"`
}
type IssueComment struct {
Body string `json:"body"`
}
type Team struct {
Name string `json:"name"`
}
type PullRequest struct {
Number int `json:"number"`
State string `json:"state"`
Title string `json:"title"`
Comments int `json:"comments"`
Commits int `json:"commits"`
Additions int `json:"additions"`
Deletions int `json:"deletions"`
ChangedFiles int `json:"changed_files"`
}
type PullRequestReviewComment struct {
File string `json:"path"`
Comment string `json:"body"`
}
type Release struct {
TagName string `json:"tag_name"`
}
type DeploymentStatus struct {
State string `json:"state"`
Description string `json:"description"`
}
type CommitCommentEvent struct {
Comment CommitComment `json:"comment"`
Repository Repository `json:"repository"`
Sender Sender `json:"sender"`
}
func (s CommitCommentEvent) NewMetric() telegraf.Metric {
event := "commit_comment"
t := map[string]string{
"event": event,
"repository": s.Repository.Repository,
"private": fmt.Sprintf("%v", s.Repository.Private),
"user": s.Sender.User,
"admin": fmt.Sprintf("%v", s.Sender.Admin),
}
f := map[string]interface{}{
"stars": s.Repository.Stars,
"forks": s.Repository.Forks,
"issues": s.Repository.Issues,
"commit": s.Comment.Commit,
"comment": s.Comment.Body,
}
m, err := telegraf.NewMetric(meas, t, f, time.Now())
if err != nil {
log.Fatalf("Failed to create %v event", event)
}
return m
}
type CreateEvent struct {
Ref string `json:"ref"`
RefType string `json:"ref_type"`
Repository Repository `json:"repository"`
Sender Sender `json:"sender"`
}
func (s CreateEvent) NewMetric() telegraf.Metric {
event := "create"
t := map[string]string{
"event": event,
"repository": s.Repository.Repository,
"private": fmt.Sprintf("%v", s.Repository.Private),
"user": s.Sender.User,
"admin": fmt.Sprintf("%v", s.Sender.Admin),
}
f := map[string]interface{}{
"stars": s.Repository.Stars,
"forks": s.Repository.Forks,
"issues": s.Repository.Issues,
"ref": s.Ref,
"refType": s.RefType,
}
m, err := telegraf.NewMetric(meas, t, f, time.Now())
if err != nil {
log.Fatalf("Failed to create %v event", event)
}
return m
}
type DeleteEvent struct {
Ref string `json:"ref"`
RefType string `json:"ref_type"`
Repository Repository `json:"repository"`
Sender Sender `json:"sender"`
}
func (s DeleteEvent) NewMetric() telegraf.Metric {
event := "delete"
t := map[string]string{
"event": event,
"repository": s.Repository.Repository,
"private": fmt.Sprintf("%v", s.Repository.Private),
"user": s.Sender.User,
"admin": fmt.Sprintf("%v", s.Sender.Admin),
}
f := map[string]interface{}{
"stars": s.Repository.Stars,
"forks": s.Repository.Forks,
"issues": s.Repository.Issues,
"ref": s.Ref,
"refType": s.RefType,
}
m, err := telegraf.NewMetric(meas, t, f, time.Now())
if err != nil {
log.Fatalf("Failed to create %v event", event)
}
return m
}
type DeploymentEvent struct {
Deployment Deployment `json:"deployment"`
Repository Repository `json:"repository"`
Sender Sender `json:"sender"`
}
func (s DeploymentEvent) NewMetric() telegraf.Metric {
event := "deployment"
t := map[string]string{
"event": event,
"repository": s.Repository.Repository,
"private": fmt.Sprintf("%v", s.Repository.Private),
"user": s.Sender.User,
"admin": fmt.Sprintf("%v", s.Sender.Admin),
}
f := map[string]interface{}{
"stars": s.Repository.Stars,
"forks": s.Repository.Forks,
"issues": s.Repository.Issues,
"commit": s.Deployment.Commit,
"task": s.Deployment.Task,
"environment": s.Deployment.Environment,
"description": s.Deployment.Description,
}
m, err := telegraf.NewMetric(meas, t, f, time.Now())
if err != nil {
log.Fatalf("Failed to create %v event", event)
}
return m
}
type DeploymentStatusEvent struct {
Deployment Deployment `json:"deployment"`
DeploymentStatus DeploymentStatus `json:"deployment_status"`
Repository Repository `json:"repository"`
Sender Sender `json:"sender"`
}
func (s DeploymentStatusEvent) NewMetric() telegraf.Metric {
event := "delete"
t := map[string]string{
"event": event,
"repository": s.Repository.Repository,
"private": fmt.Sprintf("%v", s.Repository.Private),
"user": s.Sender.User,
"admin": fmt.Sprintf("%v", s.Sender.Admin),
}
f := map[string]interface{}{
"stars": s.Repository.Stars,
"forks": s.Repository.Forks,
"issues": s.Repository.Issues,
"commit": s.Deployment.Commit,
"task": s.Deployment.Task,
"environment": s.Deployment.Environment,
"description": s.Deployment.Description,
"depState": s.DeploymentStatus.State,
"depDescription": s.DeploymentStatus.Description,
}
m, err := telegraf.NewMetric(meas, t, f, time.Now())
if err != nil {
log.Fatalf("Failed to create %v event", event)
}
return m
}
type ForkEvent struct {
Forkee Repository `json:"forkee"`
Repository Repository `json:"repository"`
Sender Sender `json:"sender"`
}
func (s ForkEvent) NewMetric() telegraf.Metric {
event := "fork"
t := map[string]string{
"event": event,
"repository": s.Repository.Repository,
"private": fmt.Sprintf("%v", s.Repository.Private),
"user": s.Sender.User,
"admin": fmt.Sprintf("%v", s.Sender.Admin),
}
f := map[string]interface{}{
"stars": s.Repository.Stars,
"forks": s.Repository.Forks,
"issues": s.Repository.Issues,
"fork": s.Forkee.Repository,
}
m, err := telegraf.NewMetric(meas, t, f, time.Now())
if err != nil {
log.Fatalf("Failed to create %v event", event)
}
return m
}
type GollumEvent struct {
Pages []Page `json:"pages"`
Repository Repository `json:"repository"`
Sender Sender `json:"sender"`
}
// REVIEW: Going to be lazy and not deal with the pages.
func (s GollumEvent) NewMetric() telegraf.Metric {
event := "gollum"
t := map[string]string{
"event": event,
"repository": s.Repository.Repository,
"private": fmt.Sprintf("%v", s.Repository.Private),
"user": s.Sender.User,
"admin": fmt.Sprintf("%v", s.Sender.Admin),
}
f := map[string]interface{}{
"stars": s.Repository.Stars,
"forks": s.Repository.Forks,
"issues": s.Repository.Issues,
}
m, err := telegraf.NewMetric(meas, t, f, time.Now())
if err != nil {
log.Fatalf("Failed to create %v event", event)
}
return m
}
type IssueCommentEvent struct {
Issue Issue `json:"issue"`
Comment IssueComment `json:"comment"`
Repository Repository `json:"repository"`
Sender Sender `json:"sender"`
}
func (s IssueCommentEvent) NewMetric() telegraf.Metric {
event := "issue_comment"
t := map[string]string{
"event": event,
"repository": s.Repository.Repository,
"private": fmt.Sprintf("%v", s.Repository.Private),
"user": s.Sender.User,
"admin": fmt.Sprintf("%v", s.Sender.Admin),
"issue": fmt.Sprintf("%v", s.Issue.Number),
}
f := map[string]interface{}{
"stars": s.Repository.Stars,
"forks": s.Repository.Forks,
"issues": s.Repository.Issues,
"title": s.Issue.Title,
"comments": s.Issue.Comments,
"body": s.Comment.Body,
}
m, err := telegraf.NewMetric(meas, t, f, time.Now())
if err != nil {
log.Fatalf("Failed to create %v event", event)
}
return m
}
type IssuesEvent struct {
Action string `json:"action"`
Issue Issue `json:"issue"`
Repository Repository `json:"repository"`
Sender Sender `json:"sender"`
}
func (s IssuesEvent) NewMetric() telegraf.Metric {
event := "issue"
t := map[string]string{
"event": event,
"repository": s.Repository.Repository,
"private": fmt.Sprintf("%v", s.Repository.Private),
"user": s.Sender.User,
"admin": fmt.Sprintf("%v", s.Sender.Admin),
"issue": fmt.Sprintf("%v", s.Issue.Number),
"action": s.Action,
}
f := map[string]interface{}{
"stars": s.Repository.Stars,
"forks": s.Repository.Forks,
"issues": s.Repository.Issues,
"title": s.Issue.Title,
"comments": s.Issue.Comments,
}
m, err := telegraf.NewMetric(meas, t, f, time.Now())
if err != nil {
log.Fatalf("Failed to create %v event", event)
}
return m
}
type MemberEvent struct {
Member Sender `json:"member"`
Repository Repository `json:"repository"`
Sender Sender `json:"sender"`
}
func (s MemberEvent) NewMetric() telegraf.Metric {
event := "member"
t := map[string]string{
"event": event,
"repository": s.Repository.Repository,
"private": fmt.Sprintf("%v", s.Repository.Private),
"user": s.Sender.User,
"admin": fmt.Sprintf("%v", s.Sender.Admin),
}
f := map[string]interface{}{
"stars": s.Repository.Stars,
"forks": s.Repository.Forks,
"issues": s.Repository.Issues,
"newMember": s.Member.User,
"newMemberStatus": s.Member.Admin,
}
m, err := telegraf.NewMetric(meas, t, f, time.Now())
if err != nil {
log.Fatalf("Failed to create %v event", event)
}
return m
}
type MembershipEvent struct {
Action string `json:"action"`
Member Sender `json:"member"`
Sender Sender `json:"sender"`
Team Team `json:"team"`
}
func (s MembershipEvent) NewMetric() telegraf.Metric {
event := "membership"
t := map[string]string{
"event": event,
"user": s.Sender.User,
"admin": fmt.Sprintf("%v", s.Sender.Admin),
"action": s.Action,
}
f := map[string]interface{}{
"newMember": s.Member.User,
"newMemberStatus": s.Member.Admin,
}
m, err := telegraf.NewMetric(meas, t, f, time.Now())
if err != nil {
log.Fatalf("Failed to create %v event", event)
}
return m
}
type PageBuildEvent struct {
Repository Repository `json:"repository"`
Sender Sender `json:"sender"`
}
func (s PageBuildEvent) NewMetric() telegraf.Metric {
event := "page_build"
t := map[string]string{
"event": event,
"repository": s.Repository.Repository,
"private": fmt.Sprintf("%v", s.Repository.Private),
"user": s.Sender.User,
"admin": fmt.Sprintf("%v", s.Sender.Admin),
}
f := map[string]interface{}{
"stars": s.Repository.Stars,
"forks": s.Repository.Forks,
"issues": s.Repository.Issues,
}
m, err := telegraf.NewMetric(meas, t, f, time.Now())
if err != nil {
log.Fatalf("Failed to create %v event", event)
}
return m
}
type PublicEvent struct {
Repository Repository `json:"repository"`
Sender Sender `json:"sender"`
}
func (s PublicEvent) NewMetric() telegraf.Metric {
event := "public"
t := map[string]string{
"event": event,
"repository": s.Repository.Repository,
"private": fmt.Sprintf("%v", s.Repository.Private),
"user": s.Sender.User,
"admin": fmt.Sprintf("%v", s.Sender.Admin),
}
f := map[string]interface{}{
"stars": s.Repository.Stars,
"forks": s.Repository.Forks,
"issues": s.Repository.Issues,
}
m, err := telegraf.NewMetric(meas, t, f, time.Now())
if err != nil {
log.Fatalf("Failed to create %v event", event)
}
return m
}
type PullRequestEvent struct {
Action string `json:"action"`
PullRequest PullRequest `json:"pull_request"`
Repository Repository `json:"repository"`
Sender Sender `json:"sender"`
}
func (s PullRequestEvent) NewMetric() telegraf.Metric {
event := "pull_request"
t := map[string]string{
"event": event,
"action": s.Action,
"repository": s.Repository.Repository,
"private": fmt.Sprintf("%v", s.Repository.Private),
"user": s.Sender.User,
"admin": fmt.Sprintf("%v", s.Sender.Admin),
"prNumber": fmt.Sprintf("%v", s.PullRequest.Number),
}
f := map[string]interface{}{
"stars": s.Repository.Stars,
"forks": s.Repository.Forks,
"issues": s.Repository.Issues,
"state": s.PullRequest.State,
"title": s.PullRequest.Title,
"comments": s.PullRequest.Comments,
"commits": s.PullRequest.Commits,
"additions": s.PullRequest.Additions,
"deletions": s.PullRequest.Deletions,
"changedFiles": s.PullRequest.ChangedFiles,
}
m, err := telegraf.NewMetric(meas, t, f, time.Now())
if err != nil {
log.Fatalf("Failed to create %v event", event)
}
return m
}
type PullRequestReviewCommentEvent struct {
Comment PullRequestReviewComment `json:"comment"`
PullRequest PullRequest `json:"pull_request"`
Repository Repository `json:"repository"`
Sender Sender `json:"sender"`
}
func (s PullRequestReviewCommentEvent) NewMetric() telegraf.Metric {
event := "pull_request_review_comment"
t := map[string]string{
"event": event,
"repository": s.Repository.Repository,
"private": fmt.Sprintf("%v", s.Repository.Private),
"user": s.Sender.User,
"admin": fmt.Sprintf("%v", s.Sender.Admin),
"prNumber": fmt.Sprintf("%v", s.PullRequest.Number),
}
f := map[string]interface{}{
"stars": s.Repository.Stars,
"forks": s.Repository.Forks,
"issues": s.Repository.Issues,
"state": s.PullRequest.State,
"title": s.PullRequest.Title,
"comments": s.PullRequest.Comments,
"commits": s.PullRequest.Commits,
"additions": s.PullRequest.Additions,
"deletions": s.PullRequest.Deletions,
"changedFiles": s.PullRequest.ChangedFiles,
"commentFile": s.Comment.File,
"comment": s.Comment.Comment,
}
m, err := telegraf.NewMetric(meas, t, f, time.Now())
if err != nil {
log.Fatalf("Failed to create %v event", event)
}
return m
}
type PushEvent struct {
Ref string `json:"ref"`
Before string `json:"before"`
After string `json:"after"`
Repository Repository `json:"repository"`
Sender Sender `json:"sender"`
}
func (s PushEvent) NewMetric() telegraf.Metric {
event := "push"
t := map[string]string{
"event": event,
"repository": s.Repository.Repository,
"private": fmt.Sprintf("%v", s.Repository.Private),
"user": s.Sender.User,
"admin": fmt.Sprintf("%v", s.Sender.Admin),
}
f := map[string]interface{}{
"stars": s.Repository.Stars,
"forks": s.Repository.Forks,
"issues": s.Repository.Issues,
"ref": s.Ref,
"before": s.Before,
"after": s.After,
}
m, err := telegraf.NewMetric(meas, t, f, time.Now())
if err != nil {
log.Fatalf("Failed to create %v event", event)
}
return m
}
type ReleaseEvent struct {
Release Release `json:"release"`
Repository Repository `json:"repository"`
Sender Sender `json:"sender"`
}
func (s ReleaseEvent) NewMetric() telegraf.Metric {
event := "release"
t := map[string]string{
"event": event,
"repository": s.Repository.Repository,
"private": fmt.Sprintf("%v", s.Repository.Private),
"user": s.Sender.User,
"admin": fmt.Sprintf("%v", s.Sender.Admin),
}
f := map[string]interface{}{
"stars": s.Repository.Stars,
"forks": s.Repository.Forks,
"issues": s.Repository.Issues,
"tagName": s.Release.TagName,
}
m, err := telegraf.NewMetric(meas, t, f, time.Now())
if err != nil {
log.Fatalf("Failed to create %v event", event)
}
return m
}
type RepositoryEvent struct {
Repository Repository `json:"repository"`
Sender Sender `json:"sender"`
}
func (s RepositoryEvent) NewMetric() telegraf.Metric {
event := "repository"
t := map[string]string{
"event": event,
"repository": s.Repository.Repository,
"private": fmt.Sprintf("%v", s.Repository.Private),
"user": s.Sender.User,
"admin": fmt.Sprintf("%v", s.Sender.Admin),
}
f := map[string]interface{}{
"stars": s.Repository.Stars,
"forks": s.Repository.Forks,
"issues": s.Repository.Issues,
}
m, err := telegraf.NewMetric(meas, t, f, time.Now())
if err != nil {
log.Fatalf("Failed to create %v event", event)
}
return m
}
type StatusEvent struct {
Commit string `json:"sha"`
State string `json:"state"`
Repository Repository `json:"repository"`
Sender Sender `json:"sender"`
}
func (s StatusEvent) NewMetric() telegraf.Metric {
event := "status"
t := map[string]string{
"event": event,
"repository": s.Repository.Repository,
"private": fmt.Sprintf("%v", s.Repository.Private),
"user": s.Sender.User,
"admin": fmt.Sprintf("%v", s.Sender.Admin),
}
f := map[string]interface{}{
"stars": s.Repository.Stars,
"forks": s.Repository.Forks,
"issues": s.Repository.Issues,
"commit": s.Commit,
"state": s.State,
}
m, err := telegraf.NewMetric(meas, t, f, time.Now())
if err != nil {
log.Fatalf("Failed to create %v event", event)
}
return m
}
type TeamAddEvent struct {
Team Team `json:"team"`
Repository Repository `json:"repository"`
Sender Sender `json:"sender"`
}
func (s TeamAddEvent) NewMetric() telegraf.Metric {
event := "team_add"
t := map[string]string{
"event": event,
"repository": s.Repository.Repository,
"private": fmt.Sprintf("%v", s.Repository.Private),
"user": s.Sender.User,
"admin": fmt.Sprintf("%v", s.Sender.Admin),
}
f := map[string]interface{}{
"stars": s.Repository.Stars,
"forks": s.Repository.Forks,
"issues": s.Repository.Issues,
"teamName": s.Team.Name,
}
m, err := telegraf.NewMetric(meas, t, f, time.Now())
if err != nil {
log.Fatalf("Failed to create %v event", event)
}
return m
}
type WatchEvent struct {
Repository Repository `json:"repository"`
Sender Sender `json:"sender"`
}
func (s WatchEvent) NewMetric() telegraf.Metric {
event := "delete"
t := map[string]string{
"event": event,
"repository": s.Repository.Repository,
"private": fmt.Sprintf("%v", s.Repository.Private),
"user": s.Sender.User,
"admin": fmt.Sprintf("%v", s.Sender.Admin),
}
f := map[string]interface{}{
"stars": s.Repository.Stars,
"forks": s.Repository.Forks,
"issues": s.Repository.Issues,
}
m, err := telegraf.NewMetric(meas, t, f, time.Now())
if err != nil {
log.Fatalf("Failed to create %v event", event)
}
return m
}

View File

@@ -0,0 +1,98 @@
package github
import (
"net/http"
"net/http/httptest"
"strings"
"testing"
"github.com/influxdata/telegraf/testutil"
)
func GithubWebhookRequest(event string, jsonString string, t *testing.T) {
var acc testutil.Accumulator
gh := &GithubWebhook{Path: "/github", acc: &acc}
req, _ := http.NewRequest("POST", "/github", strings.NewReader(jsonString))
req.Header.Add("X-Github-Event", event)
w := httptest.NewRecorder()
gh.eventHandler(w, req)
if w.Code != http.StatusOK {
t.Errorf("POST "+event+" returned HTTP status code %v.\nExpected %v", w.Code, http.StatusOK)
}
}
func TestCommitCommentEvent(t *testing.T) {
GithubWebhookRequest("commit_comment", CommitCommentEventJSON(), t)
}
func TestDeleteEvent(t *testing.T) {
GithubWebhookRequest("delete", DeleteEventJSON(), t)
}
func TestDeploymentEvent(t *testing.T) {
GithubWebhookRequest("deployment", DeploymentEventJSON(), t)
}
func TestDeploymentStatusEvent(t *testing.T) {
GithubWebhookRequest("deployment_status", DeploymentStatusEventJSON(), t)
}
func TestForkEvent(t *testing.T) {
GithubWebhookRequest("fork", ForkEventJSON(), t)
}
func TestGollumEvent(t *testing.T) {
GithubWebhookRequest("gollum", GollumEventJSON(), t)
}
func TestIssueCommentEvent(t *testing.T) {
GithubWebhookRequest("issue_comment", IssueCommentEventJSON(), t)
}
func TestIssuesEvent(t *testing.T) {
GithubWebhookRequest("issues", IssuesEventJSON(), t)
}
func TestMemberEvent(t *testing.T) {
GithubWebhookRequest("member", MemberEventJSON(), t)
}
func TestMembershipEvent(t *testing.T) {
GithubWebhookRequest("membership", MembershipEventJSON(), t)
}
func TestPageBuildEvent(t *testing.T) {
GithubWebhookRequest("page_build", PageBuildEventJSON(), t)
}
func TestPublicEvent(t *testing.T) {
GithubWebhookRequest("public", PublicEventJSON(), t)
}
func TestPullRequestReviewCommentEvent(t *testing.T) {
GithubWebhookRequest("pull_request_review_comment", PullRequestReviewCommentEventJSON(), t)
}
func TestPushEvent(t *testing.T) {
GithubWebhookRequest("push", PushEventJSON(), t)
}
func TestReleaseEvent(t *testing.T) {
GithubWebhookRequest("release", ReleaseEventJSON(), t)
}
func TestRepositoryEvent(t *testing.T) {
GithubWebhookRequest("repository", RepositoryEventJSON(), t)
}
func TestStatusEvent(t *testing.T) {
GithubWebhookRequest("status", StatusEventJSON(), t)
}
func TestTeamAddEvent(t *testing.T) {
GithubWebhookRequest("team_add", TeamAddEventJSON(), t)
}
func TestWatchEvent(t *testing.T) {
GithubWebhookRequest("watch", WatchEventJSON(), t)
}

View File

@@ -0,0 +1,38 @@
# rollbar webhooks
You should configure your Rollbar's Webhooks to point at the `webhooks` service. To do this go to `rollbar.com/` and click `Settings > Notifications > Webhook`. In the resulting page set `URL` to `http://<my_ip>:1619/rollbar`, and click on `Enable Webhook Integration`.
## Events
The titles of the following sections are links to the full payloads and details for each event. The body contains what information from the event is persisted. The format is as follows:
```
# TAGS
* 'tagKey' = `tagValue` type
# FIELDS
* 'fieldKey' = `fieldValue` type
```
The tag values and field values show the place on the incoming JSON object where the data is sourced from.
See [webhook doc](https://rollbar.com/docs/webhooks/)
#### `new_item` event
**Tags:**
* 'event' = `event.event_name` string
* 'environment' = `event.data.item.environment` string
* 'project_id = `event.data.item.project_id` int
* 'language' = `event.data.item.last_occurence.language` string
* 'level' = `event.data.item.last_occurence.level` string
**Fields:**
* 'id' = `event.data.item.id` int
#### `deploy` event
**Tags:**
* 'event' = `event.event_name` string
* 'environment' = `event.data.deploy.environment` string
* 'project_id = `event.data.deploy.project_id` int
**Fields:**
* 'id' = `event.data.item.id` int

View File

@@ -0,0 +1,69 @@
package rollbar
import (
"encoding/json"
"errors"
"io/ioutil"
"log"
"net/http"
"time"
"github.com/gorilla/mux"
"github.com/influxdata/telegraf"
)
type RollbarWebhook struct {
Path string
acc telegraf.Accumulator
}
func (rb *RollbarWebhook) Register(router *mux.Router, acc telegraf.Accumulator) {
router.HandleFunc(rb.Path, rb.eventHandler).Methods("POST")
log.Printf("Started the webhooks_rollbar on %s\n", rb.Path)
rb.acc = acc
}
func (rb *RollbarWebhook) eventHandler(w http.ResponseWriter, r *http.Request) {
defer r.Body.Close()
data, err := ioutil.ReadAll(r.Body)
if err != nil {
w.WriteHeader(http.StatusBadRequest)
return
}
dummyEvent := &DummyEvent{}
err = json.Unmarshal(data, dummyEvent)
if err != nil {
w.WriteHeader(http.StatusBadRequest)
return
}
event, err := NewEvent(dummyEvent, data)
if err != nil {
w.WriteHeader(http.StatusOK)
return
}
rb.acc.AddFields("rollbar_webhooks", event.Fields(), event.Tags(), time.Now())
w.WriteHeader(http.StatusOK)
}
func generateEvent(event Event, data []byte) (Event, error) {
err := json.Unmarshal(data, event)
if err != nil {
return nil, err
}
return event, nil
}
func NewEvent(dummyEvent *DummyEvent, data []byte) (Event, error) {
switch dummyEvent.EventName {
case "new_item":
return generateEvent(&NewItem{}, data)
case "deploy":
return generateEvent(&Deploy{}, data)
default:
return nil, errors.New("Not implemented type: " + dummyEvent.EventName)
}
}

View File

@@ -0,0 +1,78 @@
package rollbar
import "strconv"
type Event interface {
Tags() map[string]string
Fields() map[string]interface{}
}
type DummyEvent struct {
EventName string `json:"event_name"`
}
type NewItemDataItemLastOccurence struct {
Language string `json:"language"`
Level string `json:"level"`
}
type NewItemDataItem struct {
Id int `json:"id"`
Environment string `json:"environment"`
ProjectId int `json:"project_id"`
LastOccurence NewItemDataItemLastOccurence `json:"last_occurrence"`
}
type NewItemData struct {
Item NewItemDataItem `json:"item"`
}
type NewItem struct {
EventName string `json:"event_name"`
Data NewItemData `json:"data"`
}
func (ni *NewItem) Tags() map[string]string {
return map[string]string{
"event": ni.EventName,
"environment": ni.Data.Item.Environment,
"project_id": strconv.Itoa(ni.Data.Item.ProjectId),
"language": ni.Data.Item.LastOccurence.Language,
"level": ni.Data.Item.LastOccurence.Level,
}
}
func (ni *NewItem) Fields() map[string]interface{} {
return map[string]interface{}{
"id": ni.Data.Item.Id,
}
}
type DeployDataDeploy struct {
Id int `json:"id"`
Environment string `json:"environment"`
ProjectId int `json:"project_id"`
}
type DeployData struct {
Deploy DeployDataDeploy `json:"deploy"`
}
type Deploy struct {
EventName string `json:"event_name"`
Data DeployData `json:"data"`
}
func (ni *Deploy) Tags() map[string]string {
return map[string]string{
"event": ni.EventName,
"environment": ni.Data.Deploy.Environment,
"project_id": strconv.Itoa(ni.Data.Deploy.ProjectId),
}
}
func (ni *Deploy) Fields() map[string]interface{} {
return map[string]interface{}{
"id": ni.Data.Deploy.Id,
}
}

View File

@@ -0,0 +1,96 @@
package rollbar
func NewItemJSON() string {
return `
{
"event_name": "new_item",
"data": {
"item": {
"public_item_id": null,
"integrations_data": {},
"last_activated_timestamp": 1382655421,
"unique_occurrences": null,
"id": 272716944,
"environment": "production",
"title": "testing aobg98wrwe",
"last_occurrence_id": 481761639,
"last_occurrence_timestamp": 1382655421,
"platform": 0,
"first_occurrence_timestamp": 1382655421,
"project_id": 90,
"resolved_in_version": null,
"status": 1,
"hash": "c595b2ae0af9b397bb6bdafd57104ac4d5f6b382",
"last_occurrence": {
"body": {
"message": {
"body": "testing aobg98wrwe"
}
},
"uuid": "d2036647-e0b7-4cad-bc98-934831b9b6d1",
"language": "python",
"level": "error",
"timestamp": 1382655421,
"server": {
"host": "dev",
"argv": [
""
]
},
"environment": "production",
"framework": "unknown",
"notifier": {
"version": "0.5.12",
"name": "pyrollbar"
},
"metadata": {
"access_token": "",
"debug": {
"routes": {
"start_time": 1382212080401,
"counters": {
"post_item": 3274122
}
}
},
"customer_timestamp": 1382655421,
"api_server_hostname": "web6"
}
},
"framework": 0,
"total_occurrences": 1,
"level": 40,
"counter": 4,
"first_occurrence_id": 481761639,
"activating_occurrence_id": 481761639
}
}
}`
}
func DeployJSON() string {
return `
{
"event_name": "deploy",
"data": {
"deploy": {
"comment": "deploying webs",
"user_id": 1,
"finish_time": 1382656039,
"start_time": 1382656038,
"id": 187585,
"environment": "production",
"project_id": 90,
"local_username": "brian",
"revision": "e4b9b7db860b2e5ac799f8c06b9498b71ab270bb"
}
}
}`
}
func UnknowJSON() string {
return `
{
"event_name": "roger"
}`
}

View File

@@ -0,0 +1,72 @@
package rollbar
import (
"net/http"
"net/http/httptest"
"strings"
"testing"
"github.com/influxdata/telegraf/testutil"
)
func postWebhooks(rb *RollbarWebhook, eventBody string) *httptest.ResponseRecorder {
req, _ := http.NewRequest("POST", "/", strings.NewReader(eventBody))
w := httptest.NewRecorder()
w.Code = 500
rb.eventHandler(w, req)
return w
}
func TestNewItem(t *testing.T) {
var acc testutil.Accumulator
rb := &RollbarWebhook{Path: "/rollbar", acc: &acc}
resp := postWebhooks(rb, NewItemJSON())
if resp.Code != http.StatusOK {
t.Errorf("POST new_item returned HTTP status code %v.\nExpected %v", resp.Code, http.StatusOK)
}
fields := map[string]interface{}{
"id": 272716944,
}
tags := map[string]string{
"event": "new_item",
"environment": "production",
"project_id": "90",
"language": "python",
"level": "error",
}
acc.AssertContainsTaggedFields(t, "rollbar_webhooks", fields, tags)
}
func TestDeploy(t *testing.T) {
var acc testutil.Accumulator
rb := &RollbarWebhook{Path: "/rollbar", acc: &acc}
resp := postWebhooks(rb, DeployJSON())
if resp.Code != http.StatusOK {
t.Errorf("POST deploy returned HTTP status code %v.\nExpected %v", resp.Code, http.StatusOK)
}
fields := map[string]interface{}{
"id": 187585,
}
tags := map[string]string{
"event": "deploy",
"environment": "production",
"project_id": "90",
}
acc.AssertContainsTaggedFields(t, "rollbar_webhooks", fields, tags)
}
func TestUnknowItem(t *testing.T) {
rb := &RollbarWebhook{Path: "/rollbar"}
resp := postWebhooks(rb, UnknowJSON())
if resp.Code != http.StatusOK {
t.Errorf("POST unknow returned HTTP status code %v.\nExpected %v", resp.Code, http.StatusOK)
}
}

View File

@@ -0,0 +1,99 @@
package webhooks
import (
"fmt"
"log"
"net/http"
"reflect"
"github.com/gorilla/mux"
"github.com/influxdata/telegraf"
"github.com/influxdata/telegraf/plugins/inputs"
"github.com/influxdata/telegraf/plugins/inputs/webhooks/github"
"github.com/influxdata/telegraf/plugins/inputs/webhooks/rollbar"
)
type Webhook interface {
Register(router *mux.Router, acc telegraf.Accumulator)
}
func init() {
inputs.Add("webhooks", func() telegraf.Input { return NewWebhooks() })
}
type Webhooks struct {
ServiceAddress string
Github *github.GithubWebhook
Rollbar *rollbar.RollbarWebhook
}
func NewWebhooks() *Webhooks {
return &Webhooks{}
}
func (wb *Webhooks) SampleConfig() string {
return `
## Address and port to host Webhook listener on
service_address = ":1619"
[inputs.webhooks.github]
path = "/github"
[inputs.webhooks.rollbar]
path = "/rollbar"
`
}
func (wb *Webhooks) Description() string {
return "A Webhooks Event collector"
}
func (wb *Webhooks) Gather(_ telegraf.Accumulator) error {
return nil
}
func (wb *Webhooks) Listen(acc telegraf.Accumulator) {
r := mux.NewRouter()
for _, webhook := range wb.AvailableWebhooks() {
webhook.Register(r, acc)
}
err := http.ListenAndServe(fmt.Sprintf("%s", wb.ServiceAddress), r)
if err != nil {
log.Printf("Error starting server: %v", err)
}
}
// Looks for fields which implement Webhook interface
func (wb *Webhooks) AvailableWebhooks() []Webhook {
webhooks := make([]Webhook, 0)
s := reflect.ValueOf(wb).Elem()
for i := 0; i < s.NumField(); i++ {
f := s.Field(i)
if !f.CanInterface() {
continue
}
if wbPlugin, ok := f.Interface().(Webhook); ok {
if !reflect.ValueOf(wbPlugin).IsNil() {
webhooks = append(webhooks, wbPlugin)
}
}
}
return webhooks
}
func (wb *Webhooks) Start(acc telegraf.Accumulator) error {
go wb.Listen(acc)
log.Printf("Started the webhooks service on %s\n", wb.ServiceAddress)
return nil
}
func (rb *Webhooks) Stop() {
log.Println("Stopping the Webhooks service")
}

View File

@@ -0,0 +1,29 @@
package webhooks
import (
"reflect"
"testing"
"github.com/influxdata/telegraf/plugins/inputs/webhooks/github"
"github.com/influxdata/telegraf/plugins/inputs/webhooks/rollbar"
)
func TestAvailableWebhooks(t *testing.T) {
wb := NewWebhooks()
expected := make([]Webhook, 0)
if !reflect.DeepEqual(wb.AvailableWebhooks(), expected) {
t.Errorf("expected to %v.\nGot %v", expected, wb.AvailableWebhooks())
}
wb.Github = &github.GithubWebhook{Path: "/github"}
expected = append(expected, wb.Github)
if !reflect.DeepEqual(wb.AvailableWebhooks(), expected) {
t.Errorf("expected to be %v.\nGot %v", expected, wb.AvailableWebhooks())
}
wb.Rollbar = &rollbar.RollbarWebhook{Path: "/rollbar"}
expected = append(expected, wb.Rollbar)
if !reflect.DeepEqual(wb.AvailableWebhooks(), expected) {
t.Errorf("expected to be %v.\nGot %v", expected, wb.AvailableWebhooks())
}
}