-
Notifications
You must be signed in to change notification settings - Fork 5.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
add librato output plugin, update datadog plugin #322
Closed
Closed
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
# Datadog Output Plugin | ||
|
||
This plugin writes to the [Datadog Metrics API](http://docs.datadoghq.com/api/#metrics) | ||
and requires an `apikey` which can be obtained [here](https://app.datadoghq.com/account/settings#api) | ||
for the account. | ||
|
||
If the point value being sent cannot be converted to a float64, the metric is skipped. | ||
|
||
Metrics are grouped by converting any `_` characters to `.` in the Point Name. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
# Librato Output Plugin | ||
|
||
This plugin writes to the [Librato Metrics API](http://dev.librato.com/v1/metrics#metrics) | ||
and requires an `api_user` and `api_token` which can be obtained [here](https://metrics.librato.com/account/api_tokens) | ||
for the account. | ||
|
||
The `source_tag` option in the Configuration file is used to send contextual information from | ||
Point Tags to the API. | ||
|
||
If the point value being sent cannot be converted to a float64, the metric is skipped. | ||
|
||
Currently, the plugin does not send any associated Point Tags. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,165 @@ | ||
package librato | ||
|
||
import ( | ||
"bytes" | ||
"encoding/json" | ||
"fmt" | ||
"log" | ||
"net/http" | ||
|
||
"github.com/influxdb/influxdb/client/v2" | ||
"github.com/influxdb/telegraf/duration" | ||
"github.com/influxdb/telegraf/outputs" | ||
) | ||
|
||
type Librato struct { | ||
ApiUser string | ||
ApiToken string | ||
SourceTag string | ||
Timeout duration.Duration | ||
|
||
apiUrl string | ||
client *http.Client | ||
} | ||
|
||
var sampleConfig = ` | ||
# Librator API Docs | ||
# http://dev.librato.com/v1/metrics-authentication | ||
|
||
# Librato API user | ||
api_user = "telegraf@influxdb.com" # required. | ||
|
||
# Librato API token | ||
api_token = "my-secret-token" # required. | ||
|
||
# Tag Field to populate source attribute (optional) | ||
# This is typically the _hostname_ from which the metric was obtained. | ||
source_tag = "hostname" | ||
|
||
# Connection timeout. | ||
# timeout = "5s" | ||
` | ||
|
||
type Metrics struct { | ||
Gauges []*Gauge `json:"gauges"` | ||
} | ||
|
||
type Gauge struct { | ||
Name string `json:"name"` | ||
Value float64 `json:"value"` | ||
Source string `json:"source"` | ||
MeasureTime int64 `json:"measure_time"` | ||
} | ||
|
||
const librato_api = "https://metrics-api.librato.com/v1/metrics" | ||
|
||
func NewLibrato(apiUrl string) *Librato { | ||
return &Librato{ | ||
apiUrl: apiUrl, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. More in line with Go style would be "apiURL". |
||
} | ||
} | ||
|
||
func (l *Librato) Connect() error { | ||
if l.ApiUser == "" || l.ApiToken == "" { | ||
return fmt.Errorf("api_user and api_token are required fields for librato output") | ||
} | ||
l.client = &http.Client{ | ||
Timeout: l.Timeout.Duration, | ||
} | ||
return nil | ||
} | ||
|
||
func (l *Librato) Write(points []*client.Point) error { | ||
if len(points) == 0 { | ||
return nil | ||
} | ||
metrics := Metrics{} | ||
var tempGauges = make([]*Gauge, len(points)) | ||
var acceptablePoints = 0 | ||
for _, pt := range points { | ||
if gauge, err := l.buildGauge(pt); err == nil { | ||
tempGauges[acceptablePoints] = gauge | ||
acceptablePoints += 1 | ||
} else { | ||
log.Printf("unable to build Gauge for %s, skipping\n", pt.Name()) | ||
} | ||
} | ||
metrics.Gauges = make([]*Gauge, acceptablePoints) | ||
copy(metrics.Gauges, tempGauges[0:]) | ||
metricsBytes, err := json.Marshal(metrics) | ||
if err != nil { | ||
return fmt.Errorf("unable to marshal Metrics, %s\n", err.Error()) | ||
} | ||
req, err := http.NewRequest("POST", l.apiUrl, bytes.NewBuffer(metricsBytes)) | ||
if err != nil { | ||
return fmt.Errorf("unable to create http.Request, %s\n", err.Error()) | ||
} | ||
req.Header.Add("Content-Type", "application/json") | ||
req.SetBasicAuth(l.ApiUser, l.ApiToken) | ||
|
||
resp, err := l.client.Do(req) | ||
if err != nil { | ||
return fmt.Errorf("error POSTing metrics, %s\n", err.Error()) | ||
} | ||
defer resp.Body.Close() | ||
|
||
if resp.StatusCode != 200 { | ||
return fmt.Errorf("received bad status code, %d\n", resp.StatusCode) | ||
} | ||
|
||
return nil | ||
} | ||
|
||
func (l *Librato) SampleConfig() string { | ||
return sampleConfig | ||
} | ||
|
||
func (l *Librato) Description() string { | ||
return "Configuration for Librato API to send metrics to." | ||
} | ||
|
||
func (l *Librato) buildGauge(pt *client.Point) (*Gauge, error) { | ||
gauge := &Gauge{ | ||
Name: pt.Name(), | ||
MeasureTime: pt.Time().Unix(), | ||
} | ||
if err := gauge.setValue(pt.Fields()["value"]); err != nil { | ||
return gauge, fmt.Errorf("unable to extract value from Fields, %s\n", err.Error()) | ||
} | ||
if l.SourceTag != "" { | ||
if source, ok := pt.Tags()[l.SourceTag]; ok { | ||
gauge.Source = source | ||
} else { | ||
return gauge, fmt.Errorf("undeterminable Source type from Field, %s\n", l.SourceTag) | ||
} | ||
} | ||
return gauge, nil | ||
} | ||
|
||
func (g *Gauge) setValue(v interface{}) error { | ||
switch d := v.(type) { | ||
case int: | ||
g.Value = float64(int(d)) | ||
case int32: | ||
g.Value = float64(int32(d)) | ||
case int64: | ||
g.Value = float64(int64(d)) | ||
case float32: | ||
g.Value = float64(d) | ||
case float64: | ||
g.Value = float64(d) | ||
default: | ||
return fmt.Errorf("undeterminable type %+v", d) | ||
} | ||
return nil | ||
} | ||
|
||
func (l *Librato) Close() error { | ||
return nil | ||
} | ||
|
||
func init() { | ||
outputs.Add("librato", func() outputs.Output { | ||
return NewLibrato(librato_api) | ||
}) | ||
} |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Go style tends to capitalize 3-letter acronyms. So this should be APIUser.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
good to know, I assume I'd need to annotate it with
toml:"api_user"
as well?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
apiUser
would be more inline with what we would do in core.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ok, my understanding was fields needed to be exported in order to be set properly from the toml config?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm talking about the JSON encoding tag names. They can be lower case.
So be clear, the core team would write: