Skip to content

Commit 168b319

Browse files
committed
Create initial outline for Datadog exporter (#1)
* Add support for basic configuration options * Documents configuration options
1 parent 7b180b2 commit 168b319

File tree

11 files changed

+1765
-0
lines changed

11 files changed

+1765
-0
lines changed

cmd/otelcontribcol/components.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import (
2323
"github.com/open-telemetry/opentelemetry-collector-contrib/exporter/awsxrayexporter"
2424
"github.com/open-telemetry/opentelemetry-collector-contrib/exporter/azuremonitorexporter"
2525
"github.com/open-telemetry/opentelemetry-collector-contrib/exporter/carbonexporter"
26+
"github.com/open-telemetry/opentelemetry-collector-contrib/exporter/datadogexporter"
2627
"github.com/open-telemetry/opentelemetry-collector-contrib/exporter/elasticexporter"
2728
"github.com/open-telemetry/opentelemetry-collector-contrib/exporter/honeycombexporter"
2829
"github.com/open-telemetry/opentelemetry-collector-contrib/exporter/jaegerthrifthttpexporter"
@@ -112,6 +113,7 @@ func components() (component.Factories, error) {
112113
elasticexporter.NewFactory(),
113114
alibabacloudlogserviceexporter.NewFactory(),
114115
sentryexporter.NewFactory(),
116+
datadogexporter.NewFactory(),
115117
}
116118
for _, exp := range factories.Exporters {
117119
exporters = append(exporters, exp)

exporter/datadogexporter/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
include ../../Makefile.Common

exporter/datadogexporter/README.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
# Datadog Exporter
2+
3+
This exporter sends metric data to [Datadog](https://datadoghq.com).
4+
5+
## Configuration
6+
7+
The only required setting is a [Datadog API key](https://app.datadoghq.com/account/settings#api).
8+
To send your Agent data to the Datadog EU site, set the site parameter to:
9+
``` yaml
10+
site: datadoghq.eu
11+
```
12+
13+
See the sample configuration file under the `example` folder for other available options.

exporter/datadogexporter/config.go

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
// Copyright The OpenTelemetry Authors
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
package datadogexporter
16+
17+
import (
18+
"errors"
19+
"fmt"
20+
"strings"
21+
22+
"go.opentelemetry.io/collector/config/configmodels"
23+
)
24+
25+
var (
26+
unsetAPIKey = errors.New("Datadog API key is unset")
27+
)
28+
29+
// Config defines configuration for the Datadog exporter.
30+
type Config struct {
31+
configmodels.ExporterSettings `mapstructure:",squash"` // squash ensures fields are correctly decoded in embedded struct.
32+
33+
// ApiKey is the Datadog API key to associate your Agent's data with your organization.
34+
// Create a new API key here: https://app.datadoghq.com/account/settings
35+
APIKey string `mapstructure:"api_key"`
36+
37+
// Site is the site of the Datadog intake to send data to.
38+
// The default value is "datadoghq.com".
39+
Site string `mapstructure:"site"`
40+
41+
// MetricsURL is the host of the Datadog intake server to send metrics to.
42+
// If not set, the value is obtained from the Site.
43+
MetricsURL string `mapstructure:"metrics_url"`
44+
}
45+
46+
// Sanitize tries to sanitize a given configuration
47+
func (c *Config) Sanitize() error {
48+
49+
// Check API key is set
50+
if c.APIKey == "" {
51+
return unsetAPIKey
52+
}
53+
54+
// Sanitize API key
55+
c.APIKey = strings.TrimSpace(c.APIKey)
56+
57+
// Set Endpoint based on site if unset
58+
if c.MetricsURL == "" {
59+
c.MetricsURL = fmt.Sprintf("https://api.%s", c.Site)
60+
}
61+
62+
return nil
63+
}
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
// Copyright The OpenTelemetry Authors
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
package datadogexporter
16+
17+
import (
18+
"path"
19+
"testing"
20+
21+
"github.com/stretchr/testify/assert"
22+
"github.com/stretchr/testify/require"
23+
"go.opentelemetry.io/collector/component/componenttest"
24+
"go.opentelemetry.io/collector/config/configmodels"
25+
"go.opentelemetry.io/collector/config/configtest"
26+
)
27+
28+
// TestLoadConfig tests that the configuration is loaded correctly
29+
func TestLoadConfig(t *testing.T) {
30+
factories, err := componenttest.ExampleComponents()
31+
assert.NoError(t, err)
32+
33+
factory := NewFactory()
34+
factories.Exporters[typeStr] = factory
35+
cfg, err := configtest.LoadConfigFile(t, path.Join(".", "testdata", "config.yaml"), factories)
36+
37+
require.NoError(t, err)
38+
require.NotNil(t, cfg)
39+
40+
e0 := cfg.Exporters["datadog"].(*Config)
41+
err = e0.Sanitize()
42+
43+
require.NoError(t, err)
44+
assert.Equal(t, e0, &Config{
45+
ExporterSettings: configmodels.ExporterSettings{
46+
NameVal: "datadog",
47+
TypeVal: "datadog",
48+
},
49+
APIKey: "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
50+
Site: DefaultSite,
51+
MetricsEndpoint: "https://api.datadoghq.com",
52+
})
53+
54+
e1 := cfg.Exporters["datadog/2"].(*Config)
55+
err = e1.Sanitize()
56+
57+
require.NoError(t, err)
58+
assert.Equal(t, e1,
59+
&Config{
60+
ExporterSettings: configmodels.ExporterSettings{
61+
NameVal: "datadog/2",
62+
TypeVal: "datadog",
63+
},
64+
APIKey: "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
65+
Site: "datadoghq.eu",
66+
MetricsEndpoint: "https://api.datadoghq.eu",
67+
})
68+
}
69+
70+
// TestOverrideMetricsEndpoint tests that the metrics endpoint is overridden
71+
// correctly when set manually.
72+
func TestOverrideMetricsEndpoint(t *testing.T) {
73+
74+
const DebugEndpoint string = "http://localhost:8080"
75+
76+
cfg := &Config{
77+
APIKey: "notnull",
78+
Site: DefaultSite,
79+
MetricsEndpoint: DebugEndpoint,
80+
}
81+
82+
err := cfg.Sanitize()
83+
require.NoError(t, err)
84+
assert.Equal(t, cfg.MetricsEndpoint, DebugEndpoint)
85+
}
86+
87+
// TestUnsetAPIKey tests that the config sanitizing throws an error
88+
// when the API key has not been set
89+
func TestUnsetAPIKey(t *testing.T) {
90+
91+
cfg := &Config{}
92+
err := cfg.Sanitize()
93+
94+
require.Error(t, err)
95+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
receivers:
2+
examplereceiver:
3+
4+
processors:
5+
exampleprocessor:
6+
7+
exporters:
8+
datadog:
9+
## @param api_key - string - required
10+
## The Datadog API key to associate your Agent's data with your organization.
11+
## Create a new API key here: https://app.datadoghq.com/account/settings
12+
#
13+
api_key: ""
14+
15+
## @param site - string - optional - default: datadoghq.com
16+
## The site of the Datadog intake to send Agent data to.
17+
## Set to 'datadoghq.eu' to send data to the EU site.
18+
#
19+
# site: datadoghq.com
20+
21+
## @param metrics_url - string - optional - default: https://api.datadoghq.com
22+
## The host of the Datadog intake server to send metrics to, only set this option
23+
## if you need the Agent to send metrics to a custom URL, it overrides the site
24+
## setting defined in "site".
25+
#
26+
# metrics_url: https://api.datadoghq.com
27+
28+
service:
29+
pipelines:
30+
traces:
31+
receivers: [examplereceiver]
32+
processors: [exampleprocessor]
33+
exporters: [datadog]
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
// Copyright The OpenTelemetry Authors
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
package datadogexporter
15+
16+
import (
17+
"context"
18+
19+
"go.opentelemetry.io/collector/component"
20+
"go.opentelemetry.io/collector/config/configerror"
21+
"go.opentelemetry.io/collector/config/configmodels"
22+
"go.opentelemetry.io/collector/exporter/exporterhelper"
23+
)
24+
25+
const (
26+
// typeStr is the type of the exporter
27+
typeStr = "datadog"
28+
29+
// DefaultSite is the default site of the Datadog intake to send data to
30+
DefaultSite = "datadoghq.com"
31+
)
32+
33+
// NewFactory creates a Datadog exporter factory
34+
func NewFactory() component.ExporterFactory {
35+
return exporterhelper.NewFactory(
36+
typeStr,
37+
createDefaultConfig,
38+
exporterhelper.WithMetrics(CreateMetricsExporter),
39+
exporterhelper.WithTraces(CreateTracesExporter),
40+
)
41+
}
42+
43+
// createDefaultConfig creates the default exporter configuration
44+
func createDefaultConfig() configmodels.Exporter {
45+
return &Config{
46+
Site: DefaultSite,
47+
}
48+
}
49+
50+
// CreateMetricsExporter creates a metrics exporter based on this config.
51+
func CreateMetricsExporter(
52+
_ context.Context,
53+
params component.ExporterCreateParams,
54+
c configmodels.Exporter,
55+
) (component.MetricsExporter, error) {
56+
57+
cfg := c.(*Config)
58+
59+
params.Logger.Info("sanitizing Datadog metrics exporter configuration")
60+
if err := cfg.Sanitize(); err != nil {
61+
return nil, err
62+
}
63+
64+
//Metrics are not yet supported
65+
return nil, configerror.ErrDataTypeIsNotSupported
66+
}
67+
68+
// CreateTracesExporter creates a traces exporter based on this config.
69+
func CreateTracesExporter(
70+
_ context.Context,
71+
params component.ExporterCreateParams,
72+
c configmodels.Exporter) (component.TraceExporter, error) {
73+
74+
cfg := c.(*Config)
75+
76+
params.Logger.Info("sanitizing Datadog metrics exporter configuration")
77+
if err := cfg.Sanitize(); err != nil {
78+
return nil, err
79+
}
80+
81+
// Traces are not yet supported
82+
return nil, configerror.ErrDataTypeIsNotSupported
83+
}

exporter/datadogexporter/go.mod

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
module github.com/DataDog/opentelemetry-collector-contrib/exporter/datadogexporter
2+
3+
go 1.14
4+
5+
require (
6+
github.com/stretchr/testify v1.6.1
7+
go.opentelemetry.io/collector v0.7.0
8+
)

0 commit comments

Comments
 (0)