Skip to content

Commit

Permalink
[exporter/datadog] Decouple metadata pusher configuration from main c…
Browse files Browse the repository at this point in the history
…onfiguration
  • Loading branch information
mx-psi committed Mar 10, 2022
1 parent ac59baf commit c69e095
Show file tree
Hide file tree
Showing 9 changed files with 116 additions and 45 deletions.
4 changes: 2 additions & 2 deletions exporter/datadogexporter/factory.go
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ func createMetricsExporter(
if md.ResourceMetrics().Len() > 0 {
attrs = md.ResourceMetrics().At(0).Resource().Attributes()
}
go metadata.Pusher(ctx, set, cfg, attrs)
go metadata.Pusher(ctx, set, newMetadataConfigfromConfig(*cfg), attrs)
})
return nil
}
Expand Down Expand Up @@ -189,7 +189,7 @@ func createTracesExporter(
if td.ResourceSpans().Len() > 0 {
attrs = td.ResourceSpans().At(0).Resource().Attributes()
}
go metadata.Pusher(ctx, set, cfg, attrs)
go metadata.Pusher(ctx, set, newMetadataConfigfromConfig(*cfg), attrs)
})
return nil
}
Expand Down
34 changes: 34 additions & 0 deletions exporter/datadogexporter/hostmetadata.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
// 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:https://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 datadogexporter // import "github.com/open-telemetry/opentelemetry-collector-contrib/exporter/datadogexporter"

import (
"github.com/open-telemetry/opentelemetry-collector-contrib/exporter/datadogexporter/config"
"github.com/open-telemetry/opentelemetry-collector-contrib/exporter/datadogexporter/internal/metadata"
)

// newMetadataConfigfromConfig creates a new metadata pusher config from the main config.
func newMetadataConfigfromConfig(cfg config.Config) metadata.MetadataPusherConfig {
return metadata.MetadataPusherConfig{
ConfigHostname: cfg.Hostname,
ConfigTags: cfg.GetHostTags(),
MetricsEndpoint: cfg.Metrics.Endpoint,
APIKey: cfg.API.Key,
UseResourceMetadata: cfg.UseResourceMetadata,
InsecureSkipVerify: cfg.TLSSetting.InsecureSkipVerify,
TimeoutSettings: cfg.TimeoutSettings,
RetrySettings: cfg.RetrySettings,
}
}
39 changes: 39 additions & 0 deletions exporter/datadogexporter/internal/metadata/config.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
// 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:https://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 metadata // import "github.com/open-telemetry/opentelemetry-collector-contrib/exporter/datadogexporter/internal/metadata"

import (
"go.opentelemetry.io/collector/exporter/exporterhelper"
)

// MetadataPusherConfig is the configuration for the metadata pusher goroutine.
type MetadataPusherConfig struct {
// ConfigHosthame is the hostname set in the configuration of the exporter (empty if unset).
ConfigHostname string
// ConfigTags are the tags set in the configuration of the exporter (empty if unset).
ConfigTags []string
// MetricsEndpoint is the metrics endpoint.
MetricsEndpoint string
// APIKey is the API key set in configuration.
APIKey string
// UseResourceMetadata is the value of 'use_resource_metadata' on the top-level configuration.
UseResourceMetadata bool
// InsecureSkipVerify is the value of `tls.insecure_skip_verify` on the configuration.
InsecureSkipVerify bool
// TimeoutSettings of exporter.
TimeoutSettings exporterhelper.TimeoutSettings
// RetrySettings of exporter.
RetrySettings exporterhelper.RetrySettings
}
31 changes: 15 additions & 16 deletions exporter/datadogexporter/internal/metadata/metadata.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@ import (
conventions "go.opentelemetry.io/collector/model/semconv/v1.6.1"
"go.uber.org/zap"

"github.com/open-telemetry/opentelemetry-collector-contrib/exporter/datadogexporter/config"
"github.com/open-telemetry/opentelemetry-collector-contrib/exporter/datadogexporter/internal/metadata/ec2"
"github.com/open-telemetry/opentelemetry-collector-contrib/exporter/datadogexporter/internal/metadata/system"
"github.com/open-telemetry/opentelemetry-collector-contrib/exporter/datadogexporter/internal/model/attributes"
Expand Down Expand Up @@ -120,10 +119,10 @@ func metadataFromAttributes(attrs pdata.AttributeMap) *HostMetadata {
return hm
}

func fillHostMetadata(params component.ExporterCreateSettings, cfg *config.Config, hm *HostMetadata) {
func fillHostMetadata(params component.ExporterCreateSettings, mcfg MetadataPusherConfig, hm *HostMetadata) {
// Could not get hostname from attributes
if hm.InternalHostname == "" {
hostname := GetHost(params.Logger, cfg.Hostname)
hostname := GetHost(params.Logger, mcfg.ConfigHostname)
hm.InternalHostname = hostname
hm.Meta.Hostname = hostname
}
Expand All @@ -132,7 +131,7 @@ func fillHostMetadata(params component.ExporterCreateSettings, cfg *config.Confi
// since it does not come from OTEL conventions
hm.Flavor = params.BuildInfo.Command
hm.Version = params.BuildInfo.Version
hm.Tags.OTel = append(hm.Tags.OTel, cfg.GetHostTags()...)
hm.Tags.OTel = append(hm.Tags.OTel, mcfg.ConfigTags...)

// EC2 data was not set from attributes
if hm.Meta.EC2Hostname == "" {
Expand All @@ -149,19 +148,19 @@ func fillHostMetadata(params component.ExporterCreateSettings, cfg *config.Confi
}
}

func pushMetadata(cfg *config.Config, params component.ExporterCreateSettings, metadata *HostMetadata) error {
func pushMetadata(mcfg MetadataPusherConfig, params component.ExporterCreateSettings, metadata *HostMetadata) error {
if metadata.Meta.Hostname == "" {
// if the hostname is empty, don't send metadata; we don't need it.
params.Logger.Debug("Skipping host metadata since the hostname is empty")
return nil
}

path := cfg.Metrics.TCPAddr.Endpoint + "/intake"
path := mcfg.MetricsEndpoint + "/intake"
buf, _ := json.Marshal(metadata)
req, _ := http.NewRequest(http.MethodPost, path, bytes.NewBuffer(buf))
utils.SetDDHeaders(req.Header, params.BuildInfo, cfg.API.Key)
utils.SetDDHeaders(req.Header, params.BuildInfo, mcfg.APIKey)
utils.SetExtraHeaders(req.Header, utils.JSONHeaders)
client := utils.NewHTTPClient(cfg.TimeoutSettings, cfg.LimitedHTTPClientSettings)
client := utils.NewHTTPClient(mcfg.TimeoutSettings, mcfg.InsecureSkipVerify)
resp, err := client.Do(req)

if err != nil {
Expand All @@ -181,11 +180,11 @@ func pushMetadata(cfg *config.Config, params component.ExporterCreateSettings, m
return nil
}

func pushMetadataWithRetry(retrier *utils.Retrier, params component.ExporterCreateSettings, cfg *config.Config, hostMetadata *HostMetadata) {
func pushMetadataWithRetry(retrier *utils.Retrier, params component.ExporterCreateSettings, mcfg MetadataPusherConfig, hostMetadata *HostMetadata) {
params.Logger.Debug("Sending host metadata payload", zap.Any("payload", hostMetadata))

err := retrier.DoWithRetries(context.Background(), func(context.Context) error {
return pushMetadata(cfg, params, hostMetadata)
return pushMetadata(mcfg, params, hostMetadata)
})

if err != nil {
Expand All @@ -197,12 +196,12 @@ func pushMetadataWithRetry(retrier *utils.Retrier, params component.ExporterCrea
}

// Pusher pushes host metadata payloads periodically to Datadog intake
func Pusher(ctx context.Context, params component.ExporterCreateSettings, cfg *config.Config, attrs pdata.AttributeMap) {
func Pusher(ctx context.Context, params component.ExporterCreateSettings, mcfg MetadataPusherConfig, attrs pdata.AttributeMap) {
// Push metadata every 30 minutes
ticker := time.NewTicker(30 * time.Minute)
defer ticker.Stop()
defer params.Logger.Debug("Shut down host metadata routine")
retrier := utils.NewRetrier(params.Logger, cfg.RetrySettings, scrub.NewScrubber())
retrier := utils.NewRetrier(params.Logger, mcfg.RetrySettings, scrub.NewScrubber())

// Get host metadata from resources and fill missing info using our exporter.
// Currently we only retrieve it once but still send the same payload
Expand All @@ -212,20 +211,20 @@ func Pusher(ctx context.Context, params component.ExporterCreateSettings, cfg *c
// do not change over time. If this ever changes `hostMetadata`
// *must* be deep copied before calling `fillHostMetadata`.
hostMetadata := &HostMetadata{Meta: &Meta{}, Tags: &HostTags{}}
if cfg.UseResourceMetadata {
if mcfg.UseResourceMetadata {
hostMetadata = metadataFromAttributes(attrs)
}
fillHostMetadata(params, cfg, hostMetadata)
fillHostMetadata(params, mcfg, hostMetadata)

// Run one first time at startup
pushMetadataWithRetry(retrier, params, cfg, hostMetadata)
pushMetadataWithRetry(retrier, params, mcfg, hostMetadata)

for {
select {
case <-ctx.Done():
return
case <-ticker.C: // Send host metadata
pushMetadataWithRetry(retrier, params, cfg, hostMetadata)
pushMetadataWithRetry(retrier, params, mcfg, hostMetadata)
}
}
}
39 changes: 20 additions & 19 deletions exporter/datadogexporter/internal/metadata/metadata_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ import (
"go.opentelemetry.io/collector/component/componenttest"
conventions "go.opentelemetry.io/collector/model/semconv/v1.6.1"

"github.com/open-telemetry/opentelemetry-collector-contrib/exporter/datadogexporter/config"
"github.com/open-telemetry/opentelemetry-collector-contrib/exporter/datadogexporter/internal/model/attributes"
"github.com/open-telemetry/opentelemetry-collector-contrib/exporter/datadogexporter/internal/model/attributes/azure"
"github.com/open-telemetry/opentelemetry-collector-contrib/exporter/datadogexporter/internal/testutils"
Expand Down Expand Up @@ -67,14 +66,13 @@ func TestFillHostMetadata(t *testing.T) {
params := componenttest.NewNopExporterCreateSettings()
params.BuildInfo = mockBuildInfo

cfg := &config.Config{TagsConfig: config.TagsConfig{
Hostname: "hostname",
Env: "prod",
Tags: []string{"key1:tag1", "key2:tag2"},
}}
mcfg := MetadataPusherConfig{
ConfigHostname: "hostname",
ConfigTags: []string{"key1:tag1", "key2:tag2", "env:prod"},
}

metadata := &HostMetadata{Meta: &Meta{}, Tags: &HostTags{}}
fillHostMetadata(params, cfg, metadata)
fillHostMetadata(params, mcfg, metadata)

assert.Equal(t, metadata.InternalHostname, "hostname")
assert.Equal(t, metadata.Flavor, "otelcontribcol")
Expand All @@ -88,7 +86,7 @@ func TestFillHostMetadata(t *testing.T) {
Tags: &HostTags{},
}

fillHostMetadata(params, cfg, metadataWithVals)
fillHostMetadata(params, mcfg, metadataWithVals)
assert.Equal(t, metadataWithVals.InternalHostname, "my-custom-hostname")
assert.Equal(t, metadataWithVals.Flavor, "otelcontribcol")
assert.Equal(t, metadataWithVals.Version, "1.0")
Expand Down Expand Up @@ -156,7 +154,9 @@ func TestMetadataFromAttributes(t *testing.T) {
}

func TestPushMetadata(t *testing.T) {
cfg := &config.Config{API: config.APIConfig{Key: "apikey"}}
mcfg := MetadataPusherConfig{
APIKey: "apikey",
}

handler := http.NewServeMux()
handler.HandleFunc("/intake", func(w http.ResponseWriter, r *http.Request) {
Expand All @@ -174,29 +174,30 @@ func TestPushMetadata(t *testing.T) {

ts := httptest.NewServer(handler)
defer ts.Close()
cfg.Metrics.Endpoint = ts.URL
mcfg.MetricsEndpoint = ts.URL

err := pushMetadata(cfg, mockExporterCreateSettings, &mockMetadata)
err := pushMetadata(mcfg, mockExporterCreateSettings, &mockMetadata)
require.NoError(t, err)
}

func TestFailPushMetadata(t *testing.T) {
cfg := &config.Config{API: config.APIConfig{Key: "apikey"}}

mcfg := MetadataPusherConfig{
APIKey: "apikey",
}
handler := http.NewServeMux()
handler.Handle("/intake", http.NotFoundHandler())

ts := httptest.NewServer(handler)
defer ts.Close()
cfg.Metrics.Endpoint = ts.URL
mcfg.MetricsEndpoint = ts.URL

err := pushMetadata(cfg, mockExporterCreateSettings, &mockMetadata)
err := pushMetadata(mcfg, mockExporterCreateSettings, &mockMetadata)
require.Error(t, err)
}

func TestPusher(t *testing.T) {
cfg := &config.Config{
API: config.APIConfig{Key: "apikey"},
mcfg := MetadataPusherConfig{
APIKey: "apikey",
UseResourceMetadata: true,
}
params := componenttest.NewNopExporterCreateSettings()
Expand All @@ -210,9 +211,9 @@ func TestPusher(t *testing.T) {

server := testutils.DatadogServerMock()
defer server.Close()
cfg.Metrics.Endpoint = server.URL
mcfg.MetricsEndpoint = server.URL

go Pusher(ctx, params, cfg, attrs)
go Pusher(ctx, params, mcfg, attrs)

body := <-server.MetadataChan
var recvMetadata HostMetadata
Expand Down
6 changes: 2 additions & 4 deletions exporter/datadogexporter/internal/utils/http.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,6 @@ import (

"go.opentelemetry.io/collector/component"
"go.opentelemetry.io/collector/exporter/exporterhelper"

"github.com/open-telemetry/opentelemetry-collector-contrib/exporter/datadogexporter/config"
)

var (
Expand All @@ -41,7 +39,7 @@ var (
)

// NewHTTPClient returns a http.Client configured with the Agent options.
func NewHTTPClient(settings exporterhelper.TimeoutSettings, httpClientSettings config.LimitedHTTPClientSettings) *http.Client {
func NewHTTPClient(settings exporterhelper.TimeoutSettings, insecureSkipVerify bool) *http.Client {
return &http.Client{
Timeout: settings.Timeout,
Transport: &http.Transport{
Expand All @@ -53,7 +51,7 @@ func NewHTTPClient(settings exporterhelper.TimeoutSettings, httpClientSettings c
MaxIdleConns: 100,
// Not supported by intake
ForceAttemptHTTP2: false,
TLSClientConfig: &tls.Config{InsecureSkipVerify: httpClientSettings.TLSSetting.InsecureSkipVerify},
TLSClientConfig: &tls.Config{InsecureSkipVerify: insecureSkipVerify},
},
}
}
Expand Down
4 changes: 2 additions & 2 deletions exporter/datadogexporter/metrics_exporter.go
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ func translatorFromConfig(logger *zap.Logger, cfg *config.Config) (*translator.T
func newMetricsExporter(ctx context.Context, params component.ExporterCreateSettings, cfg *config.Config) (*metricsExporter, error) {
client := utils.CreateClient(cfg.API.Key, cfg.Metrics.TCPAddr.Endpoint)
client.ExtraHeader["User-Agent"] = utils.UserAgent(params.BuildInfo)
client.HttpClient = utils.NewHTTPClient(cfg.TimeoutSettings, cfg.LimitedHTTPClientSettings)
client.HttpClient = utils.NewHTTPClient(cfg.TimeoutSettings, cfg.LimitedHTTPClientSettings.TLSSetting.InsecureSkipVerify)

utils.ValidateAPIKey(params.Logger, client)

Expand Down Expand Up @@ -163,7 +163,7 @@ func (exp *metricsExporter) PushMetricsData(ctx context.Context, md pdata.Metric
if md.ResourceMetrics().Len() > 0 {
attrs = md.ResourceMetrics().At(0).Resource().Attributes()
}
go metadata.Pusher(exp.ctx, exp.params, exp.cfg, attrs)
go metadata.Pusher(exp.ctx, exp.params, newMetadataConfigfromConfig(*exp.cfg), attrs)
})
}

Expand Down
2 changes: 1 addition & 1 deletion exporter/datadogexporter/trace_connection.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ func createTraceEdgeConnection(rootURL, apiKey string, buildInfo component.Build
statsURL: rootURL + "/api/v0.2/stats",
buildInfo: buildInfo,
apiKey: apiKey,
client: utils.NewHTTPClient(settings, httpClientSettings),
client: utils.NewHTTPClient(settings, httpClientSettings.TLSSetting.InsecureSkipVerify),
}
}

Expand Down
2 changes: 1 addition & 1 deletion exporter/datadogexporter/traces_exporter.go
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ func (exp *traceExporter) pushTraceData(
if td.ResourceSpans().Len() > 0 {
attrs = td.ResourceSpans().At(0).Resource().Attributes()
}
go metadata.Pusher(exp.ctx, exp.params, exp.cfg, attrs)
go metadata.Pusher(exp.ctx, exp.params, newMetadataConfigfromConfig(*exp.cfg), attrs)
})
}

Expand Down

0 comments on commit c69e095

Please sign in to comment.