Skip to content

Commit

Permalink
Create initial outline for Datadog exporter (#1)
Browse files Browse the repository at this point in the history
* Add support for basic configuration options
* Documents configuration options
  • Loading branch information
mx-psi committed Aug 31, 2020
1 parent 7b180b2 commit 168b319
Show file tree
Hide file tree
Showing 11 changed files with 1,765 additions and 0 deletions.
2 changes: 2 additions & 0 deletions cmd/otelcontribcol/components.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import (
"github.com/open-telemetry/opentelemetry-collector-contrib/exporter/awsxrayexporter"
"github.com/open-telemetry/opentelemetry-collector-contrib/exporter/azuremonitorexporter"
"github.com/open-telemetry/opentelemetry-collector-contrib/exporter/carbonexporter"
"github.com/open-telemetry/opentelemetry-collector-contrib/exporter/datadogexporter"
"github.com/open-telemetry/opentelemetry-collector-contrib/exporter/elasticexporter"
"github.com/open-telemetry/opentelemetry-collector-contrib/exporter/honeycombexporter"
"github.com/open-telemetry/opentelemetry-collector-contrib/exporter/jaegerthrifthttpexporter"
Expand Down Expand Up @@ -112,6 +113,7 @@ func components() (component.Factories, error) {
elasticexporter.NewFactory(),
alibabacloudlogserviceexporter.NewFactory(),
sentryexporter.NewFactory(),
datadogexporter.NewFactory(),
}
for _, exp := range factories.Exporters {
exporters = append(exporters, exp)
Expand Down
1 change: 1 addition & 0 deletions exporter/datadogexporter/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
include ../../Makefile.Common
13 changes: 13 additions & 0 deletions exporter/datadogexporter/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# Datadog Exporter

This exporter sends metric data to [Datadog](https://datadoghq.com).

## Configuration

The only required setting is a [Datadog API key](https://app.datadoghq.com/account/settings#api).
To send your Agent data to the Datadog EU site, set the site parameter to:
``` yaml
site: datadoghq.eu
```
See the sample configuration file under the `example` folder for other available options.
63 changes: 63 additions & 0 deletions exporter/datadogexporter/config.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
// 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 datadogexporter

import (
"errors"
"fmt"
"strings"

"go.opentelemetry.io/collector/config/configmodels"
)

var (
unsetAPIKey = errors.New("Datadog API key is unset")
)

// Config defines configuration for the Datadog exporter.
type Config struct {
configmodels.ExporterSettings `mapstructure:",squash"` // squash ensures fields are correctly decoded in embedded struct.

// ApiKey is the Datadog API key to associate your Agent's data with your organization.
// Create a new API key here: https://app.datadoghq.com/account/settings
APIKey string `mapstructure:"api_key"`

// Site is the site of the Datadog intake to send data to.
// The default value is "datadoghq.com".
Site string `mapstructure:"site"`

// MetricsURL is the host of the Datadog intake server to send metrics to.
// If not set, the value is obtained from the Site.
MetricsURL string `mapstructure:"metrics_url"`
}

// Sanitize tries to sanitize a given configuration
func (c *Config) Sanitize() error {

// Check API key is set
if c.APIKey == "" {
return unsetAPIKey
}

// Sanitize API key
c.APIKey = strings.TrimSpace(c.APIKey)

// Set Endpoint based on site if unset
if c.MetricsURL == "" {
c.MetricsURL = fmt.Sprintf("https://api.%s", c.Site)
}

return nil
}
95 changes: 95 additions & 0 deletions exporter/datadogexporter/config_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
// 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 datadogexporter

import (
"path"
"testing"

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"go.opentelemetry.io/collector/component/componenttest"
"go.opentelemetry.io/collector/config/configmodels"
"go.opentelemetry.io/collector/config/configtest"
)

// TestLoadConfig tests that the configuration is loaded correctly
func TestLoadConfig(t *testing.T) {
factories, err := componenttest.ExampleComponents()
assert.NoError(t, err)

factory := NewFactory()
factories.Exporters[typeStr] = factory
cfg, err := configtest.LoadConfigFile(t, path.Join(".", "testdata", "config.yaml"), factories)

require.NoError(t, err)
require.NotNil(t, cfg)

e0 := cfg.Exporters["datadog"].(*Config)
err = e0.Sanitize()

require.NoError(t, err)
assert.Equal(t, e0, &Config{
ExporterSettings: configmodels.ExporterSettings{
NameVal: "datadog",
TypeVal: "datadog",
},
APIKey: "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
Site: DefaultSite,
MetricsEndpoint: "https://api.datadoghq.com",
})

e1 := cfg.Exporters["datadog/2"].(*Config)
err = e1.Sanitize()

require.NoError(t, err)
assert.Equal(t, e1,
&Config{
ExporterSettings: configmodels.ExporterSettings{
NameVal: "datadog/2",
TypeVal: "datadog",
},
APIKey: "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
Site: "datadoghq.eu",
MetricsEndpoint: "https://api.datadoghq.eu",
})
}

// TestOverrideMetricsEndpoint tests that the metrics endpoint is overridden
// correctly when set manually.
func TestOverrideMetricsEndpoint(t *testing.T) {

const DebugEndpoint string = "http://localhost:8080"

cfg := &Config{
APIKey: "notnull",
Site: DefaultSite,
MetricsEndpoint: DebugEndpoint,
}

err := cfg.Sanitize()
require.NoError(t, err)
assert.Equal(t, cfg.MetricsEndpoint, DebugEndpoint)
}

// TestUnsetAPIKey tests that the config sanitizing throws an error
// when the API key has not been set
func TestUnsetAPIKey(t *testing.T) {

cfg := &Config{}
err := cfg.Sanitize()

require.Error(t, err)
}
33 changes: 33 additions & 0 deletions exporter/datadogexporter/example/config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
receivers:
examplereceiver:

processors:
exampleprocessor:

exporters:
datadog:
## @param api_key - string - required
## The Datadog API key to associate your Agent's data with your organization.
## Create a new API key here: https://app.datadoghq.com/account/settings
#
api_key: ""

## @param site - string - optional - default: datadoghq.com
## The site of the Datadog intake to send Agent data to.
## Set to 'datadoghq.eu' to send data to the EU site.
#
# site: datadoghq.com

## @param metrics_url - string - optional - default: https://api.datadoghq.com
## The host of the Datadog intake server to send metrics to, only set this option
## if you need the Agent to send metrics to a custom URL, it overrides the site
## setting defined in "site".
#
# metrics_url: https://api.datadoghq.com

service:
pipelines:
traces:
receivers: [examplereceiver]
processors: [exampleprocessor]
exporters: [datadog]
83 changes: 83 additions & 0 deletions exporter/datadogexporter/factory.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
// 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 datadogexporter

import (
"context"

"go.opentelemetry.io/collector/component"
"go.opentelemetry.io/collector/config/configerror"
"go.opentelemetry.io/collector/config/configmodels"
"go.opentelemetry.io/collector/exporter/exporterhelper"
)

const (
// typeStr is the type of the exporter
typeStr = "datadog"

// DefaultSite is the default site of the Datadog intake to send data to
DefaultSite = "datadoghq.com"
)

// NewFactory creates a Datadog exporter factory
func NewFactory() component.ExporterFactory {
return exporterhelper.NewFactory(
typeStr,
createDefaultConfig,
exporterhelper.WithMetrics(CreateMetricsExporter),
exporterhelper.WithTraces(CreateTracesExporter),
)
}

// createDefaultConfig creates the default exporter configuration
func createDefaultConfig() configmodels.Exporter {
return &Config{
Site: DefaultSite,
}
}

// CreateMetricsExporter creates a metrics exporter based on this config.
func CreateMetricsExporter(
_ context.Context,
params component.ExporterCreateParams,
c configmodels.Exporter,
) (component.MetricsExporter, error) {

cfg := c.(*Config)

params.Logger.Info("sanitizing Datadog metrics exporter configuration")
if err := cfg.Sanitize(); err != nil {
return nil, err
}

//Metrics are not yet supported
return nil, configerror.ErrDataTypeIsNotSupported
}

// CreateTracesExporter creates a traces exporter based on this config.
func CreateTracesExporter(
_ context.Context,
params component.ExporterCreateParams,
c configmodels.Exporter) (component.TraceExporter, error) {

cfg := c.(*Config)

params.Logger.Info("sanitizing Datadog metrics exporter configuration")
if err := cfg.Sanitize(); err != nil {
return nil, err
}

// Traces are not yet supported
return nil, configerror.ErrDataTypeIsNotSupported
}
8 changes: 8 additions & 0 deletions exporter/datadogexporter/go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
module github.com/DataDog/opentelemetry-collector-contrib/exporter/datadogexporter

go 1.14

require (
github.com/stretchr/testify v1.6.1
go.opentelemetry.io/collector v0.7.0
)
Loading

0 comments on commit 168b319

Please sign in to comment.