Skip to content

Commit

Permalink
[exporter/datadogexporter] Decouple translator and exporter configura…
Browse files Browse the repository at this point in the history
  • Loading branch information
mx-psi authored Oct 4, 2021
1 parent 1bad7d5 commit bf7ff95
Show file tree
Hide file tree
Showing 10 changed files with 331 additions and 94 deletions.
7 changes: 6 additions & 1 deletion exporter/datadogexporter/factory.go
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,12 @@ func createMetricsExporter(
return nil
}
} else {
pushMetricsFn = newMetricsExporter(ctx, set, cfg).PushMetricsData
exp, err := newMetricsExporter(ctx, set, cfg)
if err != nil {
cancel()
return nil, err
}
pushMetricsFn = exp.PushMetricsData
}

exporter, err := exporterhelper.NewMetricsExporter(
Expand Down
142 changes: 142 additions & 0 deletions exporter/datadogexporter/internal/translator/config.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
// Copyright The OpenTelemetry Authors
//
// 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 translator

import "fmt"

type translatorConfig struct {
// metrics export behavior
HistMode HistogramMode
SendCountSum bool
Quantiles bool
SendMonotonic bool
ResourceAttributesAsTags bool

// cache configuration
sweepInterval int64
deltaTTL int64

// hostname provider configuration
fallbackHostnameProvider HostnameProvider
}

// Option is a translator creation option.
type Option func(*translatorConfig) error

// WithDeltaTTL sets the delta TTL for cumulative metrics datapoints.
// By default, 3600 seconds are used.
func WithDeltaTTL(deltaTTL int64) Option {
return func(t *translatorConfig) error {
if deltaTTL <= 0 {
return fmt.Errorf("time to live must be positive: %d", deltaTTL)
}
t.deltaTTL = deltaTTL
t.sweepInterval = 1
if t.deltaTTL > 1 {
t.sweepInterval = t.deltaTTL / 2
}
return nil
}
}

// WithFallbackHostnameProvider sets the fallback hostname provider.
// By default, an empty hostname is used as a fallback.
func WithFallbackHostnameProvider(provider HostnameProvider) Option {
return func(t *translatorConfig) error {
t.fallbackHostnameProvider = provider
return nil
}
}

// WithQuantiles enables quantiles exporting for summary metrics.
func WithQuantiles() Option {
return func(t *translatorConfig) error {
t.Quantiles = true
return nil
}
}

// WithResourceAttributesAsTags sets resource attributes as tags.
func WithResourceAttributesAsTags() Option {
return func(t *translatorConfig) error {
t.ResourceAttributesAsTags = true
return nil
}
}

// HistogramMode is an export mode for OTLP Histogram metrics.
type HistogramMode string

const (
// HistogramModeNoBuckets disables bucket export.
HistogramModeNoBuckets HistogramMode = "nobuckets"
// HistogramModeCounters exports buckets as Datadog counts.
HistogramModeCounters HistogramMode = "counters"
// HistogramModeDistributions exports buckets as Datadog distributions.
HistogramModeDistributions HistogramMode = "distributions"
)

// WithHistogramMode sets the histograms mode.
// The default mode is HistogramModeOff.
func WithHistogramMode(mode HistogramMode) Option {
return func(t *translatorConfig) error {

switch mode {
case HistogramModeNoBuckets, HistogramModeCounters, HistogramModeDistributions:
t.HistMode = mode
default:
return fmt.Errorf("unknown histogram mode: %q", mode)
}
return nil
}
}

// WithCountSumMetrics exports .count and .sum histogram metrics.
func WithCountSumMetrics() Option {
return func(t *translatorConfig) error {
t.SendCountSum = true
return nil
}
}

// NumberMode is an export mode for OTLP Number metrics.
type NumberMode string

const (
// NumberModeCumulativeToDelta calculates delta for
// cumulative monotonic metrics in the client side and reports
// them as Datadog counts.
NumberModeCumulativeToDelta NumberMode = "cumulative_to_delta"

// NumberModeRawValue reports the raw value for cumulative monotonic
// metrics as a Datadog gauge.
NumberModeRawValue NumberMode = "raw_value"
)

// WithNumberMode sets the number mode.
// The default mode is NumberModeCumulativeToDelta.
func WithNumberMode(mode NumberMode) Option {
return func(t *translatorConfig) error {
switch mode {
case NumberModeCumulativeToDelta:
t.SendMonotonic = true
case NumberModeRawValue:
t.SendMonotonic = false
default:
return fmt.Errorf("unknown number mode: %q", mode)
}
return nil
}
}
31 changes: 31 additions & 0 deletions exporter/datadogexporter/internal/translator/hostname_provider.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
// Copyright The OpenTelemetry Authors
//
// 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 translator

import "context"

// HostnameProvider gets a hostname
type HostnameProvider interface {
// Hostname gets the hostname from the machine.
Hostname(ctx context.Context) (string, error)
}

var _ HostnameProvider = (*noHostProvider)(nil)

type noHostProvider struct{}

func (*noHostProvider) Hostname(context.Context) (string, error) {
return "", nil
}
72 changes: 40 additions & 32 deletions exporter/datadogexporter/internal/translator/metrics_translator.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,36 +27,45 @@ import (
"go.uber.org/zap"
"gopkg.in/zorkian/go-datadog-api.v2"

"github.com/open-telemetry/opentelemetry-collector-contrib/exporter/datadogexporter/config"
"github.com/open-telemetry/opentelemetry-collector-contrib/exporter/datadogexporter/internal/attributes"
"github.com/open-telemetry/opentelemetry-collector-contrib/exporter/datadogexporter/internal/metrics"
"github.com/open-telemetry/opentelemetry-collector-contrib/exporter/datadogexporter/internal/sketches"
)

const metricName string = "metric name"

const (
histogramModeNoBuckets = "nobuckets"
histogramModeCounters = "counters"
histogramModeDistributions = "distributions"
)

// HostnameProvider gets a hostname
type HostnameProvider interface {
// Hostname gets the hostname from the machine.
Hostname(ctx context.Context) (string, error)
}

type Translator struct {
prevPts *TTLCache
logger *zap.Logger
cfg config.MetricsConfig
buildInfo component.BuildInfo
fallbackHostnameProvider HostnameProvider
prevPts *ttlCache
logger *zap.Logger
cfg translatorConfig
buildInfo component.BuildInfo
}

func New(cache *TTLCache, params component.ExporterCreateSettings, cfg config.MetricsConfig, fallbackHostProvider HostnameProvider) *Translator {
return &Translator{cache, params.Logger, cfg, params.BuildInfo, fallbackHostProvider}
func New(params component.ExporterCreateSettings, options ...Option) (*Translator, error) {
cfg := translatorConfig{
HistMode: HistogramModeDistributions,
SendCountSum: false,
Quantiles: false,
SendMonotonic: true,
ResourceAttributesAsTags: false,
sweepInterval: 1800,
deltaTTL: 3600,
fallbackHostnameProvider: &noHostProvider{},
}

for _, opt := range options {
err := opt(&cfg)
if err != nil {
return nil, err
}
}

if cfg.HistMode == HistogramModeNoBuckets && !cfg.SendCountSum {
return nil, fmt.Errorf("no buckets mode and no send count sum are incompatible")
}

cache := newTTLCache(cfg.sweepInterval, cfg.deltaTTL)
return &Translator{cache, params.Logger, cfg, params.BuildInfo}, nil
}

// getTags maps an attributeMap into a slice of Datadog tags
Expand Down Expand Up @@ -232,7 +241,7 @@ func (t *Translator) getLegacyBuckets(name string, p pdata.HistogramDataPoint, d
func (t *Translator) mapHistogramMetrics(name string, slice pdata.HistogramDataPointSlice, delta bool, attrTags []string) (ms []datadog.Metric, sl sketches.SketchSeriesList) {
// Allocate assuming none are nil and no buckets
ms = make([]datadog.Metric, 0, 2*slice.Len())
if t.cfg.HistConfig.Mode == histogramModeDistributions {
if t.cfg.HistMode == HistogramModeDistributions {
sl = make(sketches.SketchSeriesList, 0, slice.Len())
}
for i := 0; i < slice.Len(); i++ {
Expand All @@ -241,7 +250,7 @@ func (t *Translator) mapHistogramMetrics(name string, slice pdata.HistogramDataP
tags := getTags(p.Attributes())
tags = append(tags, attrTags...)

if t.cfg.HistConfig.SendCountSum {
if t.cfg.SendCountSum {
count := float64(p.Count())
countName := fmt.Sprintf("%s.count", name)
if delta {
Expand All @@ -251,7 +260,7 @@ func (t *Translator) mapHistogramMetrics(name string, slice pdata.HistogramDataP
}
}

if t.cfg.HistConfig.SendCountSum {
if t.cfg.SendCountSum {
sum := p.Sum()
sumName := fmt.Sprintf("%s.sum", name)
if !t.isSkippable(sumName, p.Sum()) {
Expand All @@ -263,10 +272,10 @@ func (t *Translator) mapHistogramMetrics(name string, slice pdata.HistogramDataP
}
}

switch t.cfg.HistConfig.Mode {
case histogramModeCounters:
switch t.cfg.HistMode {
case HistogramModeCounters:
ms = append(ms, t.getLegacyBuckets(name, p, delta, tags)...)
case histogramModeDistributions:
case HistogramModeDistributions:
sl = append(sl, t.getSketchBuckets(name, ts, p, true, tags))
}
}
Expand Down Expand Up @@ -349,7 +358,7 @@ func (t *Translator) mapSummaryMetrics(name string, slice pdata.SummaryDataPoint
}

// MapMetrics maps OTLP metrics into the DataDog format
func (t *Translator) MapMetrics(md pdata.Metrics) (series []datadog.Metric, sl sketches.SketchSeriesList) {
func (t *Translator) MapMetrics(ctx context.Context, md pdata.Metrics) (series []datadog.Metric, sl sketches.SketchSeriesList, err error) {
pushTime := uint64(time.Now().UTC().UnixNano())
rms := md.ResourceMetrics()
seenHosts := make(map[string]struct{})
Expand All @@ -360,16 +369,15 @@ func (t *Translator) MapMetrics(md pdata.Metrics) (series []datadog.Metric, sl s

// Only fetch attribute tags if they're not already converted into labels.
// Otherwise some tags would be present twice in a metric's tag list.
if !t.cfg.ExporterConfig.ResourceAttributesAsTags {
if !t.cfg.ResourceAttributesAsTags {
attributeTags = attributes.TagsFromAttributes(rm.Resource().Attributes())
}

host, ok := attributes.HostnameFromAttributes(rm.Resource().Attributes())
if !ok {
fallbackHost, err := t.fallbackHostnameProvider.Hostname(context.Background())
host = ""
if err == nil {
host = fallbackHost
host, err = t.cfg.fallbackHostnameProvider.Hostname(context.Background())
if err != nil {
return nil, nil, fmt.Errorf("failed to get fallback host: %w", err)
}
}
seenHosts[host] = struct{}{}
Expand Down
Loading

0 comments on commit bf7ff95

Please sign in to comment.