Skip to content
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

[exporter/datadog] Decouple Config structs from internal components #8375

Merged
merged 4 commits into from
Mar 18, 2022
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
[exporter/datadog] Decouple metadata pusher configuration from main c…
…onfiguration
  • Loading branch information
mx-psi committed Mar 10, 2022
commit ee8b160b8095a96c427bf293362ce209ed35ebd8
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.PusherConfig {
return metadata.PusherConfig{
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"
)

// PusherConfig is the configuration for the metadata pusher goroutine.
type PusherConfig 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 PusherConfig, 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 PusherConfig, 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 PusherConfig, 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 PusherConfig, 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 := PusherConfig{
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 := PusherConfig{
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 := PusherConfig{
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 := PusherConfig{
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