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

Update New Relic exporter. #3091

Merged
43 changes: 27 additions & 16 deletions exporter/newrelicexporter/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,42 +9,53 @@ This exporter supports sending trace and metric data to [New Relic](https://newr

## Configuration

The following configuration options are supported:
The following common configuration options are supported:

* One or both of the following are required:
* `apikey`: Your New Relic [Insights Insert API Key](https://docs.newrelic.com/docs/insights/insights-data-sources/custom-data/send-custom-events-event-api#register).
* `api_key_header`: Request header to read New Relic [Insights Insert API Key](https://docs.newrelic.com/docs/insights/insights-data-sources/custom-data/send-custom-events-event-api#register) from.
* `timeout` (Optional): Amount of time spent attempting a request before abandoning and dropping data. Default is 15 seconds.
* `common_attributes` (Optional): Attributes to apply to all metrics sent.
* `metrics_host_override` (Optional): Overrides the endpoint to send metrics.
The endpoint defaults to New Relic's US data centers. For other use cases
refer to
[OpenTelemetry: Advanced configuration](https://docs.newrelic.com/docs/integrations/open-source-telemetry-integrations/opentelemetry/opentelemetry-advanced-configuration#h2-change-endpoints).
* `spans_host_override` (Optional): Overrides the endpoint to send spans.
The endpoint defaults to New Relic's US data centers. For other use cases
refer to
[OpenTelemetry: Advanced configuration](https://docs.newrelic.com/docs/integrations/open-source-telemetry-integrations/opentelemetry/opentelemetry-advanced-configuration#h2-change-endpoints).

Example:
* `host_override` (Optional): Overrides the host to which data is sent. The URL will be generated in the form:
https://\$host/\$path. Only set the the host portion of the URL. The path component **CANNOT** be overridden.

**Basic example:**
```yaml
exporters:
newrelic:
apikey: super-secret-api-key
timeout: 30s
common_attributes:
server: prod-server-01
ready_to_rock: true
volume: 11
```

Configuration option can be overridden by telemetry signal (i.e., traces,
metrics, and logs). This is especially important if you need to use the
`host_override` option because the exporter defaults to sending data to New
Relic's US data centers. For other use cases refer to
[OpenTelemetry: Advanced configuration](https://docs.newrelic.com/docs/integrations/open-source-telemetry-integrations/opentelemetry/opentelemetry-advanced-configuration#h2-change-endpoints).

**Example of overriding options by telemetry signal:**
```yaml
exporters:
newrelic:
apikey: super-secret-api-key
timeout: 30s

# host_override is set to send data to New Relic's EU data centers.
traces:
host_override: trace-api.eu.newrelic.com
timeout: 20s
metrics:
host_override: metric-api.eu.newrelic.com
logs:
host_override: log-api.eu.newrelic.com
```

## Find and use your data

Once the exporter is sending data you can start to explore your data in New Relic:

- Metric data: see [Metric API docs](https://docs.newrelic.com/docs/data-ingest-apis/get-data-new-relic/metric-api/introduction-metric-api#find-data).
- Trace/span data: see [Trace API docs](https://docs.newrelic.com/docs/understand-dependencies/distributed-tracing/trace-api/introduction-trace-api#view-data).
- Log data: see [Log docs](https://docs.newrelic.com/docs/logs/log-management/ui-data/explore-your-data-log-analytics)

For general querying information, see:

Expand Down
84 changes: 51 additions & 33 deletions exporter/newrelicexporter/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,58 +17,76 @@ package newrelicexporter
import (
"time"

"github.com/newrelic/newrelic-telemetry-sdk-go/telemetry"
"go.opentelemetry.io/collector/config"
)

// Config defines configuration options for the New Relic exporter.
type Config struct {
*config.ExporterSettings `mapstructure:"-"`

// EndpointConfig defines configuration for a single endpoint in the New Relic exporter.
type EndpointConfig struct {
// APIKey is the required authentication credentials for New Relic APIs. This field specifies the default key.
APIKey string `mapstructure:"apikey"`

// APIKeyHeader may be specified to instruct the exporter to extract the API key from the request context.
APIKeyHeader string `mapstructure:"api_key_header"`

// HostOverride overrides the endpoint.
HostOverride string `mapstructure:"host_override"`

// Timeout is the total amount of time spent attempting a request,
// including retries, before abandoning and dropping data. Default is 15
// seconds.
Timeout time.Duration `mapstructure:"timeout"`

// CommonAttributes are the attributes to be applied to all telemetry
// sent to New Relic.
CommonAttributes map[string]interface{} `mapstructure:"common_attributes"`
// Insecure disables TLS on the endpoint.
insecure bool
}

// Config defines configuration options for the New Relic exporter.
type Config struct {
*config.ExporterSettings `mapstructure:"-"`

// CommonConfig stores the base configuration for each endpoint.
CommonConfig EndpointConfig `mapstructure:",squash"`

// MetricsHostOverride overrides the metrics endpoint.
MetricsHostOverride string `mapstructure:"metrics_host_override"`
// TracesConfig stores the configuration for the traces endpoint.
TracesConfig EndpointConfig `mapstructure:"traces"`

// SpansHostOverride overrides the spans endpoint.
SpansHostOverride string `mapstructure:"spans_host_override"`
// MetricsConfig stores the configuration for the metrics endpoint.
MetricsConfig EndpointConfig `mapstructure:"metrics"`

// MetricsInsecure disables TLS on the metrics endpoint.
metricsInsecure bool
// LogsConfig stores the configuration for the logs endpoint.
LogsConfig EndpointConfig `mapstructure:"logs"`
}

// GetTracesConfig merges the common configuration section with the traces specific section.
func (c Config) GetTracesConfig() EndpointConfig {
return mergeConfig(c.CommonConfig, c.TracesConfig)
}

// SpansInsecure disables TLS on the spans endpoint.
spansInsecure bool
// GetMetricsConfig merges the common configuration section with the metrics specific section.
func (c Config) GetMetricsConfig() EndpointConfig {
return mergeConfig(c.CommonConfig, c.MetricsConfig)
}

// HarvestOption sets all relevant Config values when instantiating a New
// Relic Harvester.
func (c Config) HarvestOption(cfg *telemetry.Config) {
cfg.APIKey = c.APIKey
cfg.HarvestPeriod = 0 // use collector harvest period.
cfg.HarvestTimeout = c.Timeout
cfg.CommonAttributes = c.CommonAttributes
cfg.Product = product
cfg.ProductVersion = version
var prefix string
if c.MetricsHostOverride != "" {
if c.metricsInsecure {
prefix = "http://"
} else {
prefix = "https://"
}
cfg.MetricsURLOverride = prefix + c.MetricsHostOverride
// GetLogsConfig merges the common configuration section with the logs specific section.
func (c Config) GetLogsConfig() EndpointConfig {
return mergeConfig(c.CommonConfig, c.LogsConfig)
}

func mergeConfig(baseConfig EndpointConfig, config EndpointConfig) EndpointConfig {
if config.APIKey == "" {
config.APIKey = baseConfig.APIKey
}

if config.APIKeyHeader == "" {
config.APIKeyHeader = baseConfig.APIKeyHeader
}

if config.HostOverride == "" {
config.HostOverride = baseConfig.HostOverride
}

if config.Timeout == 0 {
config.Timeout = baseConfig.Timeout
}
return config
}
160 changes: 129 additions & 31 deletions exporter/newrelicexporter/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ import (
"testing"
"time"

"github.com/newrelic/newrelic-telemetry-sdk-go/telemetry"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"go.opentelemetry.io/collector/component/componenttest"
Expand All @@ -46,43 +45,142 @@ func TestLoadConfig(t *testing.T) {
defaultConfig := factory.CreateDefaultConfig().(*Config)
assert.Equal(t, r0, defaultConfig)

defaultNrConfig := new(telemetry.Config)
defaultConfig.HarvestOption(defaultNrConfig)
assert.Empty(t, defaultNrConfig.MetricsURLOverride)
assert.Empty(t, defaultNrConfig.SpansURLOverride)

r1 := cfg.Exporters["newrelic/alt"].(*Config)
assert.Equal(t, r1, &Config{
ExporterSettings: &config.ExporterSettings{
TypeVal: config.Type(typeStr),
TypeVal: "newrelic",
NameVal: "newrelic/alt",
},
APIKey: "a1b2c3d4",
Timeout: time.Second * 30,
CommonAttributes: map[string]interface{}{
"server": "test-server",
"prod": true,
"weight": 3,
},
MetricsHostOverride: "alt.metrics.newrelic.com",
SpansHostOverride: "alt.spans.newrelic.com",
metricsInsecure: false,
spansInsecure: false,
CommonConfig: EndpointConfig{
APIKey: "a1b2c3d4",
Timeout: time.Second * 30,
},
MetricsConfig: EndpointConfig{
HostOverride: "alt.metrics.newrelic.com",
insecure: false,
},
TracesConfig: EndpointConfig{
HostOverride: "alt.spans.newrelic.com",
insecure: false,
},
LogsConfig: EndpointConfig{
HostOverride: "alt.logs.newrelic.com",
insecure: false,
},
})
}

nrConfig := new(telemetry.Config)
r1.HarvestOption(nrConfig)
func TestEndpointSpecificConfigTakesPrecedence(t *testing.T) {
config := Config{
CommonConfig: EndpointConfig{
APIKey: "commonapikey",
APIKeyHeader: "commonapikeyheader",
HostOverride: "commonhost",
Timeout: time.Second * 10,
},
TracesConfig: EndpointConfig{
APIKey: "tracesapikey",
APIKeyHeader: "tracesapikeyheader",
HostOverride: "traceshost",
Timeout: time.Second * 20,
},
MetricsConfig: EndpointConfig{
APIKey: "metricsapikey",
APIKeyHeader: "metricsapikeyheader",
HostOverride: "metricshost",
Timeout: time.Second * 30,
},
LogsConfig: EndpointConfig{
APIKey: "logsapikey",
APIKeyHeader: "logsapikeyheader",
HostOverride: "logshost",
Timeout: time.Second * 40,
},
}

assert.Equal(t, nrConfig, &telemetry.Config{
APIKey: "a1b2c3d4",
HarvestTimeout: time.Second * 30,
CommonAttributes: map[string]interface{}{
"server": "test-server",
"prod": true,
"weight": 3,
assert.Equal(t, config.TracesConfig, config.GetTracesConfig())
assert.Equal(t, config.MetricsConfig, config.GetMetricsConfig())
assert.Equal(t, config.LogsConfig, config.GetLogsConfig())
}

func TestEndpointSpecificConfigUsedWhenDefined(t *testing.T) {
config := Config{
CommonConfig: EndpointConfig{
APIKey: "commonapikey",
APIKeyHeader: "commonapikeyheader",
HostOverride: "commonhost",
Timeout: time.Second * 10,
},
MetricsURLOverride: "https://alt.metrics.newrelic.com",
Product: product,
ProductVersion: version,
})
TracesConfig: EndpointConfig{
APIKey: "tracesapikey",
HostOverride: "traceshost",
Timeout: time.Second * 20,
},
MetricsConfig: EndpointConfig{
APIKeyHeader: "metricsapikeyheader",
HostOverride: "metricshost",
Timeout: time.Second * 30,
},
LogsConfig: EndpointConfig{
APIKey: "logsapikey",
APIKeyHeader: "logsapikeyheader",
HostOverride: "logshost",
},
}

expectedTraceConfig := EndpointConfig{
APIKey: "tracesapikey",
APIKeyHeader: "commonapikeyheader",
HostOverride: "traceshost",
Timeout: time.Second * 20,
}
expectedMetricConfig := EndpointConfig{
APIKey: "commonapikey",
APIKeyHeader: "metricsapikeyheader",
HostOverride: "metricshost",
Timeout: time.Second * 30,
}
expectedLogConfig := EndpointConfig{
APIKey: "logsapikey",
APIKeyHeader: "logsapikeyheader",
HostOverride: "logshost",
Timeout: time.Second * 10,
}

assert.Equal(t, expectedTraceConfig, config.GetTracesConfig())
assert.Equal(t, expectedMetricConfig, config.GetMetricsConfig())
assert.Equal(t, expectedLogConfig, config.GetLogsConfig())
}

func TestCommonConfigValuesUsed(t *testing.T) {
config := Config{
CommonConfig: EndpointConfig{
APIKey: "commonapikey",
APIKeyHeader: "commonapikeyheader",
HostOverride: "commonhost",
Timeout: time.Second * 10,
},
TracesConfig: EndpointConfig{
APIKey: "",
APIKeyHeader: "",
HostOverride: "",
Timeout: 0,
},
MetricsConfig: EndpointConfig{
APIKey: "",
APIKeyHeader: "",
HostOverride: "",
Timeout: 0,
},
LogsConfig: EndpointConfig{
APIKey: "",
APIKeyHeader: "",
HostOverride: "",
Timeout: 0,
},
}

assert.Equal(t, config.CommonConfig, config.GetTracesConfig())
assert.Equal(t, config.CommonConfig, config.GetMetricsConfig())
assert.Equal(t, config.CommonConfig, config.GetLogsConfig())
}
Loading