-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
6 changed files
with
342 additions
and
1 deletion.
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
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,130 @@ | ||
package metrics | ||
|
||
import ( | ||
"fmt" | ||
"sync" | ||
"time" | ||
|
||
"github.com/DataDog/datadog-go/v5/statsd" | ||
"github.com/coopnorge/go-datadog-lib/v2/errors" | ||
"github.com/coopnorge/go-datadog-lib/v2/internal" | ||
) | ||
|
||
var ( | ||
setupOnce sync.Once | ||
setupErr error | ||
statsdClient statsd.ClientInterface | ||
errorHandler errors.ErrorHandler | ||
cfg *config | ||
) | ||
|
||
// GlobalSetup configures the Dogstatsd Client. GlobalSetup is intended to be | ||
// called from coopdatadog.Start(), but can be called directly. | ||
func GlobalSetup(options ...Option) error { | ||
setupOnce.Do(func() { | ||
if internal.IsDatadogDisabled() { | ||
statsdClient = &noopClient{} | ||
return | ||
} | ||
|
||
cfg, setupErr = resolveConfig(options) | ||
if setupErr != nil { | ||
return | ||
} | ||
|
||
if !cfg.enableMetrics { | ||
statsdClient = &noopClient{} | ||
return | ||
} | ||
|
||
statsdClient, setupErr = statsd.New(cfg.dsdEndpoint, statsd.WithTags(cfg.tags)) | ||
if setupErr != nil { | ||
return | ||
} | ||
}) | ||
return setupErr | ||
} | ||
|
||
// Flush forces a flush of all the queued dogstatsd payloads. | ||
func Flush() error { | ||
err := statsdClient.Flush() | ||
if err != nil { | ||
return fmt.Errorf("failed to flush: %w", err) | ||
} | ||
return nil | ||
} | ||
|
||
// Gauge measures the value of a metric at a particular time. | ||
func Gauge(name string, value float64, tags ...string) { | ||
err := statsdClient.Gauge(name, value, tags, cfg.metricSampleRate) | ||
if err != nil { | ||
errorHandler(fmt.Errorf("failed to send Gauge: %w", err)) | ||
} | ||
} | ||
|
||
// Count tracks how many times something happened per second. | ||
func Count(name string, value int64, tags ...string) { | ||
err := statsdClient.Count(name, value, tags, cfg.metricSampleRate) | ||
if err != nil { | ||
errorHandler(fmt.Errorf("failed to to send Count: %w", err)) | ||
} | ||
} | ||
|
||
// Histogram tracks the statistical distribution of a set of values on each host. | ||
func Histogram(name string, value float64, tags ...string) { | ||
err := statsdClient.Histogram(name, value, tags, cfg.metricSampleRate) | ||
if err != nil { | ||
errorHandler(fmt.Errorf("failed to to send Histogram: %w", err)) | ||
} | ||
} | ||
|
||
// Distribution tracks the statistical distribution of a set of values across your infrastructure. | ||
// | ||
// It is recommended to use `WithMaxBufferedMetricsPerContext` to avoid dropping metrics at high throughput, `cfg.metricSampleRate` can | ||
// also be used to limit the load. Both options can *not* be used together. | ||
func Distribution(name string, value float64, tags ...string) { | ||
err := statsdClient.Distribution(name, value, tags, cfg.metricSampleRate) | ||
if err != nil { | ||
errorHandler(fmt.Errorf("failed to to send Distribution: %w", err)) | ||
} | ||
} | ||
|
||
// Decr is just Count of -1 | ||
func Decr(name string, tags ...string) { | ||
Count(name, -1, tags...) | ||
} | ||
|
||
// Incr is just Count of 1 | ||
func Incr(name string, tags ...string) { | ||
Count(name, 1, tags...) | ||
} | ||
|
||
// Set counts the number of unique elements in a group. | ||
func Set(name string, value string, tags ...string) { | ||
err := statsdClient.Set(name, value, tags, cfg.metricSampleRate) | ||
if err != nil { | ||
errorHandler(fmt.Errorf("failed to to send Set: %w", err)) | ||
} | ||
} | ||
|
||
// Timing sends timing information, it is an alias for TimeInMilliseconds | ||
func Timing(name string, value time.Duration, tags ...string) { | ||
TimeInMilliseconds(name, value.Seconds()*1000, tags...) | ||
} | ||
|
||
// TimeInMilliseconds sends timing information in milliseconds. | ||
// It is flushed by statsd with percentiles, mean and other info (https://github.com/etsy/statsd/blob/master/docs/metric_types.md#timing) | ||
func TimeInMilliseconds(name string, value float64, tags ...string) { | ||
err := statsdClient.TimeInMilliseconds(name, value, tags, cfg.metricSampleRate) | ||
if err != nil { | ||
errorHandler(fmt.Errorf("failed to to send TimeInMilliseconds: %w", err)) | ||
} | ||
} | ||
|
||
// SimpleEvent sends an event with the provided title and text. | ||
func SimpleEvent(title, text string) { | ||
err := statsdClient.SimpleEvent(title, text) | ||
if err != nil { | ||
errorHandler(fmt.Errorf("failed to send Event: %w", err)) | ||
} | ||
} |
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,107 @@ | ||
package metrics | ||
|
||
import ( | ||
"time" | ||
|
||
"github.com/DataDog/datadog-go/v5/statsd" | ||
) | ||
|
||
// Verify that Client implements the ClientInterface. | ||
var _ statsd.ClientInterface = &noopClient{} | ||
|
||
type noopClient struct{} | ||
|
||
// Close implements statsd.ClientInterface. | ||
func (n *noopClient) Close() error { | ||
return nil | ||
} | ||
|
||
// Count implements statsd.ClientInterface. | ||
func (n *noopClient) Count(_ string, _ int64, _ []string, _ float64) error { | ||
return nil | ||
} | ||
|
||
// CountWithTimestamp implements statsd.ClientInterface. | ||
func (n *noopClient) CountWithTimestamp(_ string, _ int64, _ []string, _ float64, _ time.Time) error { | ||
return nil | ||
} | ||
|
||
// Decr implements statsd.ClientInterface. | ||
func (n *noopClient) Decr(_ string, _ []string, _ float64) error { | ||
return nil | ||
} | ||
|
||
// Distribution implements statsd.ClientInterface. | ||
func (n *noopClient) Distribution(_ string, _ float64, _ []string, _ float64) error { | ||
return nil | ||
} | ||
|
||
// Event implements statsd.ClientInterface. | ||
func (n *noopClient) Event(_ *statsd.Event) error { | ||
return nil | ||
} | ||
|
||
// Flush implements statsd.ClientInterface. | ||
func (n *noopClient) Flush() error { | ||
return nil | ||
} | ||
|
||
// Gauge implements statsd.ClientInterface. | ||
func (n *noopClient) Gauge(_ string, _ float64, _ []string, _ float64) error { | ||
return nil | ||
} | ||
|
||
// GaugeWithTimestamp implements statsd.ClientInterface. | ||
func (n *noopClient) GaugeWithTimestamp(_ string, _ float64, _ []string, _ float64, _ time.Time) error { | ||
return nil | ||
} | ||
|
||
// GetTelemetry implements statsd.ClientInterface. | ||
func (n *noopClient) GetTelemetry() statsd.Telemetry { | ||
return statsd.Telemetry{} | ||
} | ||
|
||
// Histogram implements statsd.ClientInterface. | ||
func (n *noopClient) Histogram(_ string, _ float64, _ []string, _ float64) error { | ||
return nil | ||
} | ||
|
||
// Incr implements statsd.ClientInterface. | ||
func (n *noopClient) Incr(_ string, _ []string, _ float64) error { | ||
return nil | ||
} | ||
|
||
// IsClosed implements statsd.ClientInterface. | ||
func (n *noopClient) IsClosed() bool { | ||
return true | ||
} | ||
|
||
// ServiceCheck implements statsd.ClientInterface. | ||
func (n *noopClient) ServiceCheck(_ *statsd.ServiceCheck) error { | ||
return nil | ||
} | ||
|
||
// Set implements statsd.ClientInterface. | ||
func (n *noopClient) Set(_ string, _ string, _ []string, _ float64) error { | ||
return nil | ||
} | ||
|
||
// SimpleEvent implements statsd.ClientInterface. | ||
func (n *noopClient) SimpleEvent(_ string, _ string) error { | ||
return nil | ||
} | ||
|
||
// SimpleServiceCheck implements statsd.ClientInterface. | ||
func (n *noopClient) SimpleServiceCheck(_ string, _ statsd.ServiceCheckStatus) error { | ||
return nil | ||
} | ||
|
||
// TimeInMilliseconds implements statsd.ClientInterface. | ||
func (n *noopClient) TimeInMilliseconds(_ string, _ float64, _ []string, _ float64) error { | ||
return nil | ||
} | ||
|
||
// Timing implements statsd.ClientInterface. | ||
func (n *noopClient) Timing(_ string, _ time.Duration, _ []string, _ float64) error { | ||
return nil | ||
} |
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,86 @@ | ||
package metrics | ||
|
||
import ( | ||
"fmt" | ||
"os" | ||
|
||
"github.com/coopnorge/go-datadog-lib/v2/errors" | ||
"github.com/coopnorge/go-datadog-lib/v2/internal" | ||
"github.com/coopnorge/go-logger" | ||
) | ||
|
||
const ( | ||
defaultEnableMetrics = true | ||
defaultMetricSampleRate = 1 | ||
) | ||
|
||
// Option is used to configure the behaviour of the metrics integration. | ||
type Option func(*config) error | ||
|
||
type config struct { | ||
enableMetrics bool | ||
errorHandler errors.ErrorHandler | ||
dsdEndpoint string | ||
metricSampleRate float64 | ||
tags []string | ||
} | ||
|
||
func resolveConfig(options []Option) (*config, error) { | ||
err := internal.VerifyEnvVarsSet( | ||
internal.DatadogDSDEndpoint, | ||
internal.DatadogEnvironment, | ||
internal.DatadogService, | ||
internal.DatadogVersion, | ||
) | ||
if err != nil { | ||
return nil, err | ||
} | ||
cfg := &config{ | ||
enableMetrics: internal.GetBool(internal.DatadogEnableMetrics, defaultEnableMetrics), | ||
errorHandler: func(err error) { | ||
logger.WithError(err).Error(err.Error()) | ||
}, | ||
dsdEndpoint: os.Getenv(internal.DatadogDSDEndpoint), | ||
metricSampleRate: defaultMetricSampleRate, | ||
tags: []string{ | ||
fmt.Sprintf("environment:%s", os.Getenv(internal.DatadogEnvironment)), | ||
fmt.Sprintf("service:%s", os.Getenv(internal.DatadogService)), | ||
fmt.Sprintf("version:%s", os.Getenv(internal.DatadogVersion)), | ||
}, | ||
} | ||
|
||
for _, option := range options { | ||
err = option(cfg) | ||
if err != nil { | ||
return nil, err | ||
} | ||
} | ||
|
||
return cfg, nil | ||
} | ||
|
||
// WithTags sets the tags that are sent with every metric, shorthand for | ||
// statsd.WithTags() | ||
func WithTags(tags ...string) Option { | ||
return func(cfg *config) error { | ||
cfg.tags = tags | ||
return nil | ||
} | ||
} | ||
|
||
// WithMetricSampleRate sets the sampling rate for metrics | ||
func WithMetricSampleRate(rate float64) Option { | ||
return func(cfg *config) error { | ||
cfg.metricSampleRate = rate | ||
return nil | ||
} | ||
} | ||
|
||
// WithErrorHandler allows for setting a custom ErrorHandler to be called on | ||
// function that may error but does not return an error | ||
func WithErrorHandler(handler errors.ErrorHandler) Option { | ||
return func(cfg *config) error { | ||
cfg.errorHandler = handler | ||
return nil | ||
} | ||
} |
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