From 30e9f313a529913b51f61c1d3124f7784a3f2877 Mon Sep 17 00:00:00 2001 From: jack-berg Date: Tue, 10 May 2022 11:27:25 -0500 Subject: [PATCH 1/2] Drop newrelicexporter --- .github/CODEOWNERS | 1 - .github/dependabot.yml | 4 - CHANGELOG.md | 2 + cmd/configschema/go.mod | 4 - exporter/newrelicexporter/Makefile | 1 - exporter/newrelicexporter/README.md | 69 -- exporter/newrelicexporter/config.go | 91 -- exporter/newrelicexporter/config_test.go | 83 -- exporter/newrelicexporter/errors.go | 157 --- exporter/newrelicexporter/errors_test.go | 195 ---- exporter/newrelicexporter/factory.go | 149 --- exporter/newrelicexporter/factory_test.go | 137 --- exporter/newrelicexporter/go.mod | 47 - exporter/newrelicexporter/go.sum | 335 ------- exporter/newrelicexporter/metrics.go | 257 ----- exporter/newrelicexporter/metrics_test.go | 429 -------- exporter/newrelicexporter/mock_test.go | 129 --- exporter/newrelicexporter/newrelic.go | 383 ------- exporter/newrelicexporter/newrelic_test.go | 939 ----------------- .../newrelicexporter/testdata/config.yaml | 37 - exporter/newrelicexporter/transformer.go | 436 -------- exporter/newrelicexporter/transformer_test.go | 942 ------------------ go.mod | 4 - go.sum | 2 - internal/components/components.go | 2 - internal/components/exporters_test.go | 9 - versions.yaml | 1 - 27 files changed, 2 insertions(+), 4843 deletions(-) delete mode 100644 exporter/newrelicexporter/Makefile delete mode 100644 exporter/newrelicexporter/README.md delete mode 100644 exporter/newrelicexporter/config.go delete mode 100644 exporter/newrelicexporter/config_test.go delete mode 100644 exporter/newrelicexporter/errors.go delete mode 100644 exporter/newrelicexporter/errors_test.go delete mode 100644 exporter/newrelicexporter/factory.go delete mode 100644 exporter/newrelicexporter/factory_test.go delete mode 100644 exporter/newrelicexporter/go.mod delete mode 100644 exporter/newrelicexporter/go.sum delete mode 100644 exporter/newrelicexporter/metrics.go delete mode 100644 exporter/newrelicexporter/metrics_test.go delete mode 100644 exporter/newrelicexporter/mock_test.go delete mode 100644 exporter/newrelicexporter/newrelic.go delete mode 100644 exporter/newrelicexporter/newrelic_test.go delete mode 100644 exporter/newrelicexporter/testdata/config.yaml delete mode 100644 exporter/newrelicexporter/transformer.go delete mode 100644 exporter/newrelicexporter/transformer_test.go diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index a07d202e386f..828de3ad08de 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -43,7 +43,6 @@ exporter/kafkaexporter/ @open-telemetry/collector-c exporter/loadbalancingexporter/ @open-telemetry/collector-contrib-approvers @jpkrohling exporter/logzioexporter/ @open-telemetry/collector-contrib-approvers @jkowall @Doron-Bargo @yotamloe exporter/lokiexporter/ @open-telemetry/collector-contrib-approvers @gramidt @jpkrohling -exporter/newrelicexporter/ @open-telemetry/collector-contrib-approvers @alanwest @jack-berg @nrcventura exporter/observiqexporter/ @open-telemetry/collector-contrib-approvers @binaryfissiongames exporter/prometheusexporter/ @open-telemetry/collector-contrib-approvers @Aneurysm9 exporter/prometheusremotewriteexporter/ @open-telemetry/collector-contrib-approvers @Aneurysm9 diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 72f6f0ddd28f..b0dc0425e73f 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -138,10 +138,6 @@ updates: directory: "/exporter/lokiexporter" schedule: interval: "weekly" - - package-ecosystem: "gomod" - directory: "/exporter/newrelicexporter" - schedule: - interval: "weekly" - package-ecosystem: "gomod" directory: "/exporter/observiqexporter" schedule: diff --git a/CHANGELOG.md b/CHANGELOG.md index 83613424733f..6b9acdcf9e98 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,8 @@ ### 🛑 Breaking changes 🛑 +- `newrelicexporter` deleted. Use New Relic native OTLP ingest instead. + ### 🚩 Deprecations 🚩 - `exporter/azuremonitor`: Deprecate use of LogRecord.Name as the log envelope category name. There is no replacement. diff --git a/cmd/configschema/go.mod b/cmd/configschema/go.mod index 106a4193a37b..dbe79e1c65c9 100644 --- a/cmd/configschema/go.mod +++ b/cmd/configschema/go.mod @@ -218,7 +218,6 @@ require ( github.com/mostynb/go-grpc-compression v1.1.16 // indirect github.com/mrunalp/fileutils v0.5.0 // indirect github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f // indirect - github.com/newrelic/newrelic-telemetry-sdk-go v0.8.1 // indirect github.com/observiq/ctimefmt v1.0.0 // indirect github.com/olivere/elastic v6.2.37+incompatible // indirect github.com/open-telemetry/opentelemetry-collector-contrib/exporter/alibabacloudlogserviceexporter v0.50.0 // indirect @@ -247,7 +246,6 @@ require ( github.com/open-telemetry/opentelemetry-collector-contrib/exporter/loadbalancingexporter v0.50.0 // indirect github.com/open-telemetry/opentelemetry-collector-contrib/exporter/logzioexporter v0.50.0 // indirect github.com/open-telemetry/opentelemetry-collector-contrib/exporter/lokiexporter v0.50.0 // indirect - github.com/open-telemetry/opentelemetry-collector-contrib/exporter/newrelicexporter v0.50.0 // indirect github.com/open-telemetry/opentelemetry-collector-contrib/exporter/opencensusexporter v0.50.0 // indirect github.com/open-telemetry/opentelemetry-collector-contrib/exporter/parquetexporter v0.50.0 // indirect github.com/open-telemetry/opentelemetry-collector-contrib/exporter/prometheusexporter v0.50.0 // indirect @@ -586,8 +584,6 @@ replace github.com/open-telemetry/opentelemetry-collector-contrib/exporter/logzi replace github.com/open-telemetry/opentelemetry-collector-contrib/exporter/lokiexporter => ../../exporter/lokiexporter -replace github.com/open-telemetry/opentelemetry-collector-contrib/exporter/newrelicexporter => ../../exporter/newrelicexporter - replace github.com/open-telemetry/opentelemetry-collector-contrib/exporter/opencensusexporter => ../../exporter/opencensusexporter replace github.com/open-telemetry/opentelemetry-collector-contrib/exporter/parquetexporter => ../../exporter/parquetexporter diff --git a/exporter/newrelicexporter/Makefile b/exporter/newrelicexporter/Makefile deleted file mode 100644 index ded7a36092dc..000000000000 --- a/exporter/newrelicexporter/Makefile +++ /dev/null @@ -1 +0,0 @@ -include ../../Makefile.Common diff --git a/exporter/newrelicexporter/README.md b/exporter/newrelicexporter/README.md deleted file mode 100644 index 0335429a976f..000000000000 --- a/exporter/newrelicexporter/README.md +++ /dev/null @@ -1,69 +0,0 @@ -# Deprecated New Relic Exporter - -New Relic native OTLP ingest became Generally Available in September 2021. This vendor specific exporter is being deprecated and will become unavailable May 1st 2022. - -To send OpenTelemetry data to New Relic, use the [OTLP gRPC Exporter](https://github.com/open-telemetry/opentelemetry-collector/tree/main/exporter/otlpexporter) instead, with configuration as [described here](https://docs.newrelic.com/docs/more-integrations/open-source-telemetry-integrations/opentelemetry/opentelemetry-quick-start/#export). - -## Overview - -This exporter supports sending trace, metric, and log data to [New Relic](https://newrelic.com/) - -> Please review the Collector's [security -> documentation](https://github.com/open-telemetry/opentelemetry-collector/blob/main/docs/security.md), -> which contains recommendations on securing sensitive information such as the -> API key required by this exporter. - -## Configuration - -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. -* `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 -``` - -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: - -- [Query New Relic data](https://docs.newrelic.com/docs/using-new-relic/data/understand-data/query-new-relic-data) -- [Intro to NRQL](https://docs.newrelic.com/docs/query-data/nrql-new-relic-query-language/getting-started/nrql-syntax-clauses-functions) diff --git a/exporter/newrelicexporter/config.go b/exporter/newrelicexporter/config.go deleted file mode 100644 index 7ec1e9fb3c3d..000000000000 --- a/exporter/newrelicexporter/config.go +++ /dev/null @@ -1,91 +0,0 @@ -// 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 newrelicexporter // import "github.com/open-telemetry/opentelemetry-collector-contrib/exporter/newrelicexporter" - -import ( - "go.opentelemetry.io/collector/config" - "go.opentelemetry.io/collector/exporter/exporterhelper" -) - -// 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"` - - // TimeoutSettings is the total amount of time spent attempting a request, - // including retries, before abandoning and dropping data. Default is 5 - // seconds. - TimeoutSettings exporterhelper.TimeoutSettings `mapstructure:",squash"` - - // RetrySettings defines configuration for retrying batches in case of export failure. - // The current supported strategy is exponential backoff. - RetrySettings exporterhelper.RetrySettings `mapstructure:"retry"` - - // Insecure disables TLS on the endpoint. - insecure bool -} - -// Config defines configuration options for the New Relic exporter. -type Config struct { - config.ExporterSettings `mapstructure:",squash"` - - // CommonConfig stores the base configuration for each endpoint. - CommonConfig EndpointConfig `mapstructure:",squash"` - - // TracesConfig stores the configuration for the traces endpoint. - TracesConfig EndpointConfig `mapstructure:"traces"` - - // MetricsConfig stores the configuration for the metrics endpoint. - MetricsConfig EndpointConfig `mapstructure:"metrics"` - - // LogsConfig stores the configuration for the logs endpoint. - LogsConfig EndpointConfig `mapstructure:"logs"` -} - -func (c *Config) Unmarshal(componentSection *config.Map) error { - if err := componentSection.UnmarshalExact(c); err != nil { - return err - } - - baseEndpointConfig := c.CommonConfig - endpointConfigs := map[string]*EndpointConfig{ - "metrics": &c.MetricsConfig, - "traces": &c.TracesConfig, - "logs": &c.LogsConfig, - } - - for section, sectionCfg := range endpointConfigs { - - // Default to whatever the common config is - *sectionCfg = baseEndpointConfig - - p, err := componentSection.Sub(section) - if err != nil { - return err - } - - // Overlay with the section specific configuration - if err := p.UnmarshalExact(sectionCfg); err != nil { - return err - } - } - return nil -} diff --git a/exporter/newrelicexporter/config_test.go b/exporter/newrelicexporter/config_test.go deleted file mode 100644 index 4c21c949e4a3..000000000000 --- a/exporter/newrelicexporter/config_test.go +++ /dev/null @@ -1,83 +0,0 @@ -// 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 newrelicexporter - -import ( - "path/filepath" - "testing" - "time" - - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - "go.opentelemetry.io/collector/component/componenttest" - "go.opentelemetry.io/collector/config" - "go.opentelemetry.io/collector/exporter/exporterhelper" - "go.opentelemetry.io/collector/service/servicetest" -) - -func TestLoadConfig(t *testing.T) { - factories, err := componenttest.NopFactories() - assert.Nil(t, err) - - factory := NewFactory() - factories.Exporters[typeStr] = factory - cfg, err := servicetest.LoadConfigAndValidate(filepath.Join("testdata", "config.yaml"), factories) - - require.NoError(t, err) - require.NotNil(t, cfg) - - assert.Equal(t, len(cfg.Exporters), 2) - - r0 := cfg.Exporters[config.NewComponentID(typeStr)] - defaultConfig := factory.CreateDefaultConfig().(*Config) - - // The marshaller should set the endpoint specific configuration to the common config by default - defaultConfig.TracesConfig = defaultConfig.CommonConfig - defaultConfig.LogsConfig = defaultConfig.CommonConfig - defaultConfig.MetricsConfig = defaultConfig.CommonConfig - assert.Equal(t, r0, defaultConfig) - - r1 := cfg.Exporters[config.NewComponentIDWithName(typeStr, "alt")].(*Config) - assert.Equal(t, r1, &Config{ - ExporterSettings: config.NewExporterSettings(config.NewComponentIDWithName(typeStr, "alt")), - CommonConfig: EndpointConfig{ - APIKey: "a1b2c3d4", - TimeoutSettings: exporterhelper.TimeoutSettings{ - Timeout: 30 * time.Second, - }, - }, - MetricsConfig: EndpointConfig{ - APIKey: "a1b2c3d4", - TimeoutSettings: exporterhelper.TimeoutSettings{ - Timeout: 30 * time.Second, - }, - HostOverride: "alt.metrics.newrelic.com", - }, - TracesConfig: EndpointConfig{ - APIKey: "a1b2c3d4", - TimeoutSettings: exporterhelper.TimeoutSettings{ - Timeout: 30 * time.Second, - }, - HostOverride: "alt.spans.newrelic.com", - }, - LogsConfig: EndpointConfig{ - APIKey: "a1b2c3d4", - TimeoutSettings: exporterhelper.TimeoutSettings{ - Timeout: 30 * time.Second, - }, - HostOverride: "alt.logs.newrelic.com", - }, - }) -} diff --git a/exporter/newrelicexporter/errors.go b/exporter/newrelicexporter/errors.go deleted file mode 100644 index 1e92f02c293a..000000000000 --- a/exporter/newrelicexporter/errors.go +++ /dev/null @@ -1,157 +0,0 @@ -// 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 newrelicexporter // import "github.com/open-telemetry/opentelemetry-collector-contrib/exporter/newrelicexporter" - -import ( - "fmt" - "net/http" - "net/url" - "strconv" - "time" - - "github.com/golang/protobuf/ptypes/duration" - "go.opentelemetry.io/collector/consumer/consumererror" - "go.opentelemetry.io/collector/exporter/exporterhelper" - "google.golang.org/genproto/googleapis/rpc/errdetails" - "google.golang.org/grpc/codes" - grpcStatus "google.golang.org/grpc/status" -) - -type urlError struct { - err error -} - -func (e *urlError) Error() string { return e.err.Error() } -func (e *urlError) Unwrap() error { return e.err } - -func (e *urlError) GRPCStatus() *grpcStatus.Status { - urlError := e.err.(*url.Error) - // If error is temporary, return retryable DataLoss code - if urlError.Temporary() { - return grpcStatus.New(codes.DataLoss, urlError.Error()) - } - // Else, return non-retryable Internal code - return grpcStatus.New(codes.Internal, urlError.Error()) -} - -func (e *urlError) IsPermanent() bool { - urlError := e.err.(*url.Error) - return !urlError.Temporary() -} - -func (e *urlError) Wrap() error { - var out error - out = e - if e.IsPermanent() { - out = consumererror.NewPermanent(out) - } - return out -} - -// Explicit mapping for the error status codes describe by the trace API: -// https://docs.newrelic.com/docs/understand-dependencies/distributed-tracing/trace-api/trace-api-general-requirements-limits#response-validation -var httpGrpcMapping = map[int]codes.Code{ - http.StatusBadRequest: codes.InvalidArgument, - http.StatusForbidden: codes.Unauthenticated, - http.StatusNotFound: codes.NotFound, - http.StatusMethodNotAllowed: codes.InvalidArgument, - http.StatusRequestTimeout: codes.DeadlineExceeded, - http.StatusLengthRequired: codes.InvalidArgument, - http.StatusRequestEntityTooLarge: codes.InvalidArgument, - http.StatusRequestURITooLong: codes.InvalidArgument, - http.StatusUnsupportedMediaType: codes.InvalidArgument, - http.StatusTooManyRequests: codes.Unavailable, - http.StatusRequestHeaderFieldsTooLarge: codes.InvalidArgument, - http.StatusInternalServerError: codes.DataLoss, - http.StatusBadGateway: codes.DataLoss, - http.StatusServiceUnavailable: codes.DataLoss, -} - -var retryableHTTPCodes = map[int]struct{}{ - http.StatusRequestTimeout: {}, - http.StatusTooManyRequests: {}, - http.StatusInternalServerError: {}, - http.StatusBadGateway: {}, - http.StatusServiceUnavailable: {}, -} - -type httpError struct { - err error - response *http.Response -} - -func (e *httpError) Unwrap() error { return e.err } -func (e *httpError) Error() string { return e.err.Error() } - -func (e *httpError) GRPCStatus() *grpcStatus.Status { - mapEntry, ok := httpGrpcMapping[e.response.StatusCode] - // If no explicit mapping exists, return retryable DataLoss code - if !ok { - return grpcStatus.New(codes.DataLoss, e.response.Status) - } - // The OTLP spec uses the Unavailable code to signal backpressure to the client - // If the http status maps to Unavailable, attempt to extract and communicate retry info to the client - retrySeconds := int64(e.ThrottleDelay().Seconds()) - if retrySeconds > 0 { - message := &errdetails.RetryInfo{RetryDelay: &duration.Duration{Seconds: retrySeconds}} - status, statusErr := grpcStatus.New(codes.Unavailable, e.response.Status).WithDetails(message) - if statusErr == nil { - return status - } - } - - // Generate an error with the mapped code, and a message containing the server's response status string - return grpcStatus.New(mapEntry, e.response.Status) -} - -func newHTTPError(response *http.Response) *httpError { - return &httpError{ - err: fmt.Errorf("new relic HTTP call failed. Status Code: %d", response.StatusCode), - response: response, - } -} - -func (e *httpError) IsPermanent() bool { - if _, ok := retryableHTTPCodes[e.response.StatusCode]; ok { - return false - } - return true -} - -func (e *httpError) ThrottleDelay() time.Duration { - if e.response.StatusCode == http.StatusTooManyRequests { - retryAfter := e.response.Header.Get("Retry-After") - if retrySeconds, err := strconv.ParseInt(retryAfter, 10, 64); err == nil { - return time.Duration(retrySeconds) * time.Second - } - } - return 0 -} - -func (e *httpError) Wrap() error { - if e.IsPermanent() { - out := consumererror.NewPermanent(e.err) - return &httpError{err: out, response: e.response} - } else if delay := e.ThrottleDelay(); delay > 0 { - // NOTE: a retry-after header means that the error is not - // permanent (by definition). Here, we use an else if to - // optimize the branch conditions. If an error is permanent, - // there's no reason to check for a throttle delay. - out := exporterhelper.NewThrottleRetry(e.err, delay) - return &httpError{err: out, response: e.response} - } else { - return e - } -} diff --git a/exporter/newrelicexporter/errors_test.go b/exporter/newrelicexporter/errors_test.go deleted file mode 100644 index e2c67cdd0a4a..000000000000 --- a/exporter/newrelicexporter/errors_test.go +++ /dev/null @@ -1,195 +0,0 @@ -// 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 newrelicexporter - -import ( - "errors" - "fmt" - "net/http" - "net/url" - "testing" - "time" - - "github.com/golang/protobuf/ptypes/duration" - "github.com/stretchr/testify/assert" - "go.opentelemetry.io/collector/exporter/exporterhelper" - "google.golang.org/genproto/googleapis/rpc/errdetails" - "google.golang.org/grpc/codes" - "google.golang.org/grpc/status" -) - -func TestHttpError_GRPCStatus(t *testing.T) { - tests := []struct { - name string - statusCode int - wantCode codes.Code - }{ - { - name: "Bad Request", - statusCode: http.StatusBadRequest, - wantCode: codes.InvalidArgument, - }, - { - name: "Forbidden", - statusCode: http.StatusForbidden, - wantCode: codes.Unauthenticated, - }, - { - name: "Internal", - statusCode: http.StatusInternalServerError, - wantCode: codes.DataLoss, - }, - { - name: "Teapot", - statusCode: http.StatusTeapot, - wantCode: codes.DataLoss, - }, - } - - for _, test := range tests { - t.Run(test.name, func(t *testing.T) { - httpResponse := responseOf(test.statusCode) - httpError := &httpError{response: httpResponse, err: errors.New("uh oh")} - got := httpError.GRPCStatus() - assert.Equal(t, test.wantCode, got.Code()) - assert.Equal(t, httpResponse.Status, got.Message()) - }) - } - - t.Run("Retry-After Bad Header", func(t *testing.T) { - response := responseOf(http.StatusTooManyRequests) - response.Header.Add("Retry-After", "foo") - assert.Equal( - t, - status.New(codes.Unavailable, http.StatusText(http.StatusTooManyRequests)), - (&httpError{response: response}).GRPCStatus(), - ) - }) - - t.Run("Retry-After Good Header", func(t *testing.T) { - response := responseOf(http.StatusTooManyRequests) - response.Header.Add("Retry-After", "10") - expectedMessage := &errdetails.RetryInfo{RetryDelay: &duration.Duration{Seconds: 10}} - expectedStatus, _ := status.New(codes.Unavailable, http.StatusText(http.StatusTooManyRequests)).WithDetails(expectedMessage) - assert.Equal( - t, - expectedStatus, - newHTTPError(response).GRPCStatus(), - ) - }) -} - -func TestHttpErrorWrapGeneratesThrottleRetryOn429StatusCode(t *testing.T) { - expected := exporterhelper.NewThrottleRetry( - fmt.Errorf("new relic HTTP call failed. Status Code: 429"), - time.Duration(10)*time.Second) - - response := responseOf(http.StatusTooManyRequests) - response.Header.Add("Retry-After", "10") - - httpError := newHTTPError(response) - wrappedErr := httpError.Wrap() - actual := errors.Unwrap(wrappedErr) - - assert.EqualValues(t, expected, actual) -} - -func TestHttpError_Error(t *testing.T) { - httpError := newHTTPError(responseOf(http.StatusTeapot)) - assert.Equal(t, httpError.Error(), "new relic HTTP call failed. Status Code: 418") -} - -func responseOf(statusCode int) *http.Response { - return &http.Response{ - StatusCode: statusCode, - Status: http.StatusText(statusCode), - Header: http.Header{}, - } -} - -type myError struct { - temporary bool -} - -func (e *myError) Error() string { return "uh oh" } -func (e *myError) Temporary() bool { return e.temporary } - -func TestUrlError_GRPCStatus(t *testing.T) { - tests := []struct { - name string - err error - wantCode codes.Code - }{ - { - name: "Temporary", - err: &url.Error{ - Op: "Get", - Err: &myError{temporary: true}, - }, - wantCode: codes.DataLoss, - }, - { - name: "No-Retry", - err: &url.Error{ - Op: "Get", - Err: &myError{temporary: false}, - }, - wantCode: codes.Internal, - }, - } - - for _, test := range tests { - t.Run(test.name, func(t *testing.T) { - err := &urlError{err: test.err} - got := err.GRPCStatus() - assert.Equal(t, test.wantCode, got.Code()) - assert.Equal(t, "Get \"\": uh oh", got.Message()) - }) - } -} - -func TestUrlError_Error(t *testing.T) { - netErr := &url.Error{ - Op: "Get", - Err: errors.New("uh oh"), - } - err := &urlError{err: netErr} - assert.Equal(t, netErr.Error(), err.Error()) -} - -func TestUrlError_Unwrap(t *testing.T) { - netErr := &url.Error{ - Op: "Get", - Err: errors.New("uh oh"), - } - err := &urlError{err: netErr} - assert.Equal(t, netErr, err.Unwrap()) -} - -func TestFromGrpcErrorHttpError(t *testing.T) { - httpError := newHTTPError(responseOf(http.StatusTeapot)) - _, ok := status.FromError(httpError) - assert.True(t, ok) -} - -func TestFromGrpcErrorUrlError(t *testing.T) { - netErr := &url.Error{ - Op: "Get", - Err: errors.New("uh oh"), - } - err := &urlError{err: netErr} - _, ok := status.FromError(err) - assert.True(t, ok) -} diff --git a/exporter/newrelicexporter/factory.go b/exporter/newrelicexporter/factory.go deleted file mode 100644 index 7f6638fd7503..000000000000 --- a/exporter/newrelicexporter/factory.go +++ /dev/null @@ -1,149 +0,0 @@ -// 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 newrelicexporter // import "github.com/open-telemetry/opentelemetry-collector-contrib/exporter/newrelicexporter" - -import ( - "context" - "fmt" - "sync" - - "github.com/newrelic/newrelic-telemetry-sdk-go/telemetry" - "go.opencensus.io/stats/view" - "go.opentelemetry.io/collector/component" - "go.opentelemetry.io/collector/config" - "go.opentelemetry.io/collector/exporter/exporterhelper" - "go.uber.org/zap" -) - -const typeStr = "newrelic" - -var once sync.Once - -// NewFactory creates a factory for New Relic exporter. -func NewFactory() component.ExporterFactory { - view.Register(MetricViews()...) - - return component.NewExporterFactory( - typeStr, - createDefaultConfig, - component.WithTracesExporter(createTracesExporter), - component.WithMetricsExporter(createMetricsExporter), - component.WithLogsExporter(createLogsExporter), - ) -} - -func logDeprecation(logger *zap.Logger) { - once.Do(func() { - logger.Warn("newrelic exporter is deprecated. Use otlp exporter instead.") - }) -} - -func createDefaultConfig() config.Exporter { - defaultRetry := exporterhelper.NewDefaultRetrySettings() - return &Config{ - ExporterSettings: config.NewExporterSettings(config.NewComponentID(typeStr)), - - CommonConfig: EndpointConfig{ - TimeoutSettings: exporterhelper.NewDefaultTimeoutSettings(), - RetrySettings: defaultRetry, - }, - } -} - -// CreateTracesExporter creates a New Relic trace exporter for this configuration. -func createTracesExporter( - _ context.Context, - set component.ExporterCreateSettings, - cfg config.Exporter, -) (component.TracesExporter, error) { - logDeprecation(set.Logger) - - nrConfig, ok := cfg.(*Config) - if !ok { - return nil, fmt.Errorf("invalid config: %#v", cfg) - } - traceConfig := nrConfig.TracesConfig - exp, err := newExporter(set.Logger, &set.BuildInfo, traceConfig, telemetry.NewSpanRequestFactory) - if err != nil { - return nil, err - } - - // The logger is only used in a disabled queuedRetrySender, which noisily logs at - // the error level when it is disabled and errors occur. - set.Logger = zap.NewNop() - return exporterhelper.NewTracesExporter(cfg, set, exp.pushTraceData, - exporterhelper.WithTimeout(traceConfig.TimeoutSettings), - exporterhelper.WithRetry(traceConfig.RetrySettings), - exporterhelper.WithQueue(exporterhelper.QueueSettings{Enabled: false}), - ) -} - -// CreateMetricsExporter creates a New Relic metrics exporter for this configuration. -func createMetricsExporter( - _ context.Context, - set component.ExporterCreateSettings, - cfg config.Exporter, -) (component.MetricsExporter, error) { - logDeprecation(set.Logger) - - nrConfig, ok := cfg.(*Config) - if !ok { - return nil, fmt.Errorf("invalid config: %#v", cfg) - } - - metricsConfig := nrConfig.MetricsConfig - exp, err := newExporter(set.Logger, &set.BuildInfo, metricsConfig, telemetry.NewMetricRequestFactory) - if err != nil { - return nil, err - } - - // The logger is only used in a disabled queuedRetrySender, which noisily logs at - // the error level when it is disabled and errors occur. - set.Logger = zap.NewNop() - return exporterhelper.NewMetricsExporter(cfg, set, exp.pushMetricData, - exporterhelper.WithTimeout(metricsConfig.TimeoutSettings), - exporterhelper.WithRetry(metricsConfig.RetrySettings), - exporterhelper.WithQueue(exporterhelper.QueueSettings{Enabled: false}), - ) -} - -// CreateLogsExporter creates a New Relic logs exporter for this configuration. -func createLogsExporter( - _ context.Context, - set component.ExporterCreateSettings, - cfg config.Exporter, -) (component.LogsExporter, error) { - logDeprecation(set.Logger) - - nrConfig, ok := cfg.(*Config) - if !ok { - return nil, fmt.Errorf("invalid config: %#v", cfg) - } - - logsConfig := nrConfig.LogsConfig - exp, err := newExporter(set.Logger, &set.BuildInfo, logsConfig, telemetry.NewLogRequestFactory) - if err != nil { - return nil, err - } - - // The logger is only used in a disabled queuedRetrySender, which noisily logs at - // the error level when it is disabled and errors occur. - set.Logger = zap.NewNop() - return exporterhelper.NewLogsExporter(cfg, set, exp.pushLogData, - exporterhelper.WithTimeout(logsConfig.TimeoutSettings), - exporterhelper.WithRetry(logsConfig.RetrySettings), - exporterhelper.WithQueue(exporterhelper.QueueSettings{Enabled: false}), - ) -} diff --git a/exporter/newrelicexporter/factory_test.go b/exporter/newrelicexporter/factory_test.go deleted file mode 100644 index 719c85eca85b..000000000000 --- a/exporter/newrelicexporter/factory_test.go +++ /dev/null @@ -1,137 +0,0 @@ -// 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 newrelicexporter - -import ( - "context" - "testing" - "time" - - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - "go.opentelemetry.io/collector/component/componenttest" - "go.opentelemetry.io/collector/config/configtest" -) - -func TestCreateDefaultConfig(t *testing.T) { - cfg := createDefaultConfig() - assert.NotNil(t, cfg, "failed to create default config") - require.NoError(t, configtest.CheckConfigStruct(cfg)) - - nrCfg, ok := cfg.(*Config) - require.True(t, ok, "invalid Config: %#v", cfg) - assert.Equal(t, nrCfg.CommonConfig.TimeoutSettings.Timeout, time.Second*5) -} - -func TestCreateExporterWithAPIKey(t *testing.T) { - cfg := createDefaultConfig() - nrConfig := cfg.(*Config) - nrConfig.MetricsConfig.APIKey = "a1b2c3d4" - nrConfig.TracesConfig.APIKey = "a1b2c3d4" - nrConfig.LogsConfig.APIKey = "a1b2c3d4" - params := componenttest.NewNopExporterCreateSettings() - - te, err := createTracesExporter(context.Background(), params, nrConfig) - assert.Nil(t, err) - assert.NotNil(t, te, "failed to create trace exporter") - - me, err := createMetricsExporter(context.Background(), params, nrConfig) - assert.Nil(t, err) - assert.NotNil(t, me, "failed to create metrics exporter") - - le, err := createLogsExporter(context.Background(), params, nrConfig) - assert.Nil(t, err) - assert.NotNil(t, le, "failed to create logs exporter") -} - -func TestCreateExporterWithAPIKeyHeader(t *testing.T) { - cfg := createDefaultConfig() - nrConfig := cfg.(*Config) - nrConfig.MetricsConfig.APIKeyHeader = "api-key" - nrConfig.TracesConfig.APIKeyHeader = "api-key" - nrConfig.LogsConfig.APIKeyHeader = "api-key" - params := componenttest.NewNopExporterCreateSettings() - - te, err := createTracesExporter(context.Background(), params, nrConfig) - assert.Nil(t, err) - assert.NotNil(t, te, "failed to create trace exporter") - - me, err := createMetricsExporter(context.Background(), params, nrConfig) - assert.Nil(t, err) - assert.NotNil(t, me, "failed to create metrics exporter") - - le, err := createLogsExporter(context.Background(), params, nrConfig) - assert.Nil(t, err) - assert.NotNil(t, le, "failed to create logs exporter") -} - -func TestCreateExporterWithAPIKeyAndAPIKeyHeader(t *testing.T) { - cfg := createDefaultConfig() - nrConfig := cfg.(*Config) - nrConfig.MetricsConfig.APIKey = "a1b2c3d4" - nrConfig.TracesConfig.APIKey = "a1b2c3d4" - nrConfig.LogsConfig.APIKey = "a1b2c3d4" - nrConfig.MetricsConfig.APIKeyHeader = "api-key" - nrConfig.TracesConfig.APIKeyHeader = "api-key" - nrConfig.LogsConfig.APIKeyHeader = "api-key" - params := componenttest.NewNopExporterCreateSettings() - - te, err := createTracesExporter(context.Background(), params, nrConfig) - assert.Nil(t, err) - assert.NotNil(t, te, "failed to create trace exporter") - - me, err := createMetricsExporter(context.Background(), params, nrConfig) - assert.Nil(t, err) - assert.NotNil(t, me, "failed to create metrics exporter") - - le, err := createLogsExporter(context.Background(), params, nrConfig) - assert.Nil(t, err) - assert.NotNil(t, le, "failed to create logs exporter") -} - -func TestCreateExporterErrorWithoutAPIKeyOrAPIKeyHeader(t *testing.T) { - cfg := createDefaultConfig() - nrConfig := cfg.(*Config) - params := componenttest.NewNopExporterCreateSettings() - - te, err := createTracesExporter(context.Background(), params, nrConfig) - assert.NotNil(t, err) - assert.Nil(t, te) - - me, err := createMetricsExporter(context.Background(), params, nrConfig) - assert.NotNil(t, err) - assert.Nil(t, me) - - le, err := createLogsExporter(context.Background(), params, nrConfig) - assert.NotNil(t, err) - assert.Nil(t, le) -} -func TestCreateTracesExporterError(t *testing.T) { - params := componenttest.NewNopExporterCreateSettings() - _, err := createTracesExporter(context.Background(), params, nil) - assert.Error(t, err) -} - -func TestCreateMetricsExporterError(t *testing.T) { - params := componenttest.NewNopExporterCreateSettings() - _, err := createMetricsExporter(context.Background(), params, nil) - assert.Error(t, err) -} - -func TestCreateLogsExporterError(t *testing.T) { - params := componenttest.NewNopExporterCreateSettings() - _, err := createLogsExporter(context.Background(), params, nil) - assert.Error(t, err) -} diff --git a/exporter/newrelicexporter/go.mod b/exporter/newrelicexporter/go.mod deleted file mode 100644 index 9c0e47e3d584..000000000000 --- a/exporter/newrelicexporter/go.mod +++ /dev/null @@ -1,47 +0,0 @@ -module github.com/open-telemetry/opentelemetry-collector-contrib/exporter/newrelicexporter - -go 1.17 - -require ( - github.com/census-instrumentation/opencensus-proto v0.3.0 - github.com/golang/protobuf v1.5.2 - github.com/newrelic/newrelic-telemetry-sdk-go v0.8.1 - github.com/open-telemetry/opentelemetry-collector-contrib/pkg/translator/opencensus v0.50.0 - github.com/stretchr/testify v1.7.1 - go.opencensus.io v0.23.0 - go.opentelemetry.io/collector v0.50.0 - go.opentelemetry.io/collector/pdata v0.50.0 - go.opentelemetry.io/collector/semconv v0.50.0 - go.uber.org/multierr v1.8.0 - go.uber.org/zap v1.21.0 - google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa - google.golang.org/grpc v1.46.0 - google.golang.org/protobuf v1.28.0 -) - -require ( - github.com/cenkalti/backoff/v4 v4.1.3 // indirect - github.com/davecgh/go-spew v1.1.1 // indirect - github.com/gogo/protobuf v1.3.2 // indirect - github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect - github.com/grpc-ecosystem/grpc-gateway v1.16.0 // indirect - github.com/knadh/koanf v1.4.1 // indirect - github.com/mitchellh/copystructure v1.2.0 // indirect - github.com/mitchellh/mapstructure v1.5.0 // indirect - github.com/mitchellh/reflectwalk v1.0.2 // indirect - github.com/open-telemetry/opentelemetry-collector-contrib/internal/coreinternal v0.50.0 // indirect - github.com/pmezard/go-difflib v1.0.0 // indirect - go.opentelemetry.io/otel v1.6.3 // indirect - go.opentelemetry.io/otel/metric v0.29.0 // indirect - go.opentelemetry.io/otel/trace v1.6.3 // indirect - go.uber.org/atomic v1.9.0 // indirect - golang.org/x/net v0.0.0-20220225172249-27dd8689420f // indirect - golang.org/x/sys v0.0.0-20220412211240-33da011f77ad // indirect - golang.org/x/text v0.3.7 // indirect - gopkg.in/yaml.v2 v2.4.0 // indirect - gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect -) - -replace github.com/open-telemetry/opentelemetry-collector-contrib/pkg/translator/opencensus => ../../pkg/translator/opencensus - -replace github.com/open-telemetry/opentelemetry-collector-contrib/internal/coreinternal => ../../internal/coreinternal diff --git a/exporter/newrelicexporter/go.sum b/exporter/newrelicexporter/go.sum deleted file mode 100644 index 85d2e656deef..000000000000 --- a/exporter/newrelicexporter/go.sum +++ /dev/null @@ -1,335 +0,0 @@ -cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= -github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= -github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= -github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= -github.com/aws/aws-sdk-go-v2 v1.9.2/go.mod h1:cK/D0BBs0b/oWPIcX/Z/obahJK1TT7IPVjy53i/mX/4= -github.com/aws/aws-sdk-go-v2/config v1.8.3/go.mod h1:4AEiLtAb8kLs7vgw2ZV3p2VZ1+hBavOc84hqxVNpCyw= -github.com/aws/aws-sdk-go-v2/credentials v1.4.3/go.mod h1:FNNC6nQZQUuyhq5aE5c7ata8o9e4ECGmS4lAXC7o1mQ= -github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.6.0/go.mod h1:gqlclDEZp4aqJOancXK6TN24aKhT0W0Ae9MHk3wzTMM= -github.com/aws/aws-sdk-go-v2/internal/ini v1.2.4/go.mod h1:ZcBrrI3zBKlhGFNYWvju0I3TR93I7YIgAfy82Fh4lcQ= -github.com/aws/aws-sdk-go-v2/service/appconfig v1.4.2/go.mod h1:FZ3HkCe+b10uFZZkFdvf98LHW21k49W8o8J366lqVKY= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.3.2/go.mod h1:72HRZDLMtmVQiLG2tLfQcaWLCssELvGl+Zf2WVxMmR8= -github.com/aws/aws-sdk-go-v2/service/sso v1.4.2/go.mod h1:NBvT9R1MEF+Ud6ApJKM0G+IkPchKS7p7c2YPKwHmBOk= -github.com/aws/aws-sdk-go-v2/service/sts v1.7.2/go.mod h1:8EzeIqfWt2wWT4rJVu3f21TfrhJ8AEMzVybRNSb/b4g= -github.com/aws/smithy-go v1.8.0/go.mod h1:SObp3lf9smib00L/v3U2eAKG8FyQ7iLrJnQiAmR5n+E= -github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= -github.com/benbjohnson/clock v1.3.0 h1:ip6w0uFQkncKQ979AypyG0ER7mqUSBdKLOgAle/AT8A= -github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= -github.com/cenkalti/backoff/v4 v4.1.3 h1:cFAlzYUlVYDysBEH2T5hyJZMh3+5+WCBvSnK6Q8UtC4= -github.com/cenkalti/backoff/v4 v4.1.3/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw= -github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= -github.com/census-instrumentation/opencensus-proto v0.3.0 h1:t/LhUZLVitR1Ow2YOnduCsavhwFUklBMoGVYUCqmCqk= -github.com/census-instrumentation/opencensus-proto v0.3.0/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= -github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= -github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= -github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= -github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= -github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI= -github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/cncf/xds/go v0.0.0-20211001041855-01bcc9b48dfe/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= -github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= -github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= -github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= -github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= -github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ= -github.com/envoyproxy/go-control-plane v0.10.2-0.20220325020618-49ff273808a1/go.mod h1:KJwIaB5Mv44NWtYuAOFCVOjcI94vtpEz2JU/D2v6IjE= -github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= -github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= -github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M= -github.com/felixge/httpsnoop v1.0.2 h1:+nS9g82KMXccJ/wp0zyRW9ZBHFETmMGtkk+2CTTrW4o= -github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= -github.com/fsnotify/fsnotify v1.5.4 h1:jRbGcIw6P2Meqdwuo0H1p6JVLbL5DHKAKlYndzMwVZI= -github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= -github.com/go-ldap/ldap v3.0.2+incompatible/go.mod h1:qfd9rJvER9Q0/D/Sqn1DfHRoBp40uXYvFoEVrNEPqRc= -github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= -github.com/go-logr/logr v1.2.3 h1:2DntVwHkVopvECVRSlL5PSo9eG+cAkDCuckLubN+rq0= -github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= -github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= -github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= -github.com/go-test/deep v1.0.2-0.20181118220953-042da051cf31/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA= -github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= -github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= -github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= -github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= -github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= -github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= -github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= -github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= -github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= -github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= -github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= -github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= -github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= -github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= -github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= -github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= -github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= -github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= -github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= -github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= -github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.7 h1:81/ik6ipDQS2aGcBfIN5dHDB36BwrStyeAQquSYCV4o= -github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE= -github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/grpc-ecosystem/grpc-gateway v1.16.0 h1:gmcG1KaJ57LophUzW0Hy8NmPhnMZb4M0+kPpLofRdBo= -github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= -github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= -github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= -github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= -github.com/hashicorp/go-hclog v0.0.0-20180709165350-ff2cf002a8dd/go.mod h1:9bjs9uLqI8l75knNv3lV1kA55veR+WUPSiKIWcQHudI= -github.com/hashicorp/go-hclog v0.8.0/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ= -github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= -github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= -github.com/hashicorp/go-plugin v1.0.1/go.mod h1:++UyYGoz3o5w9ZzAdZxtQKrWWP+iqPBn3cQptSMzBuY= -github.com/hashicorp/go-retryablehttp v0.5.4/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= -github.com/hashicorp/go-rootcerts v1.0.1/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8= -github.com/hashicorp/go-sockaddr v1.0.2/go.mod h1:rB4wwRAUzs07qva3c5SdrY/NEtAUjGlgmH/UkBUC97A= -github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= -github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= -github.com/hashicorp/go-version v1.1.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= -github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= -github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= -github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= -github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= -github.com/hashicorp/vault/api v1.0.4/go.mod h1:gDcqh3WGcR1cpF5AJz/B1UFheUEneMoIospckxBxk6Q= -github.com/hashicorp/vault/sdk v0.1.13/go.mod h1:B+hVj7TpuQY1Y/GPbCpffmgd+tSEwvhkWnjtSYCaS2M= -github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb/go.mod h1:+NfK9FKeTrX5uv1uIXGdwYDTeHna2qgaIlx54MXqjAM= -github.com/hashicorp/yamux v0.0.0-20181012175058-2f1d1f20f75d/go.mod h1:+NfK9FKeTrX5uv1uIXGdwYDTeHna2qgaIlx54MXqjAM= -github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= -github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= -github.com/joho/godotenv v1.3.0 h1:Zjp+RcGpHhGlrMbJzXTrZZPrWj+1vfm90La1wgB6Bhc= -github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg= -github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= -github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= -github.com/klauspost/compress v1.15.1 h1:y9FcTHGyrebwfP0ZZqFiaxTaiDnUrGkJkI+f583BL1A= -github.com/knadh/koanf v1.4.1 h1:Z0VGW/uo8NJmjd+L1Dc3S5frq6c62w5xQ9Yf4Mg3wFQ= -github.com/knadh/koanf v1.4.1/go.mod h1:1cfH5223ZeZUOs8FU2UdTmaNfHpqgtjV0+NHjRO43gs= -github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= -github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= -github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= -github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= -github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= -github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= -github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= -github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw= -github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= -github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= -github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= -github.com/mitchellh/go-testing-interface v0.0.0-20171004221916-a61a99592b77/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= -github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= -github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= -github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= -github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= -github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= -github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= -github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= -github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= -github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= -github.com/mostynb/go-grpc-compression v1.1.16 h1:D9tGUINmcII049pxOj9dl32Fzhp26TrDVQXECoKJqQg= -github.com/newrelic/newrelic-telemetry-sdk-go v0.8.1 h1:6OX5VXMuj2salqNBc41eXKz6K+nV6OB/hhlGnAKCbwU= -github.com/newrelic/newrelic-telemetry-sdk-go v0.8.1/go.mod h1:2kY6OeOxrJ+RIQlVjWDc/pZlT3MIf30prs6drzMfJ6E= -github.com/npillmayer/nestext v0.1.3/go.mod h1:h2lrijH8jpicr25dFY+oAJLyzlya6jhnuG+zWp9L0Uk= -github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA= -github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= -github.com/pelletier/go-toml v1.7.0/go.mod h1:vwGMzjaWMwyfHwgIBhI2YUM4fB6nL6lVAvS1LBMMhTE= -github.com/pelletier/go-toml v1.9.4 h1:tjENF6MfZAg8e4ZmZTeWaWiT2vXtsoO6+iuOjFhECwM= -github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= -github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= -github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= -github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= -github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/rhnvrm/simples3 v0.6.1/go.mod h1:Y+3vYm2V7Y4VijFoJHHTrja6OgPrJ2cBti8dPGkC3sA= -github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= -github.com/rogpeppe/go-internal v1.6.1 h1:/FiVV8dS/e+YqF2JvO3yXRFbBLTIuSDkuC7aBOAvL+k= -github.com/rs/cors v1.8.2 h1:KCooALfAYGs415Cwu5ABvv9n9509fSiG5SQJn/AQo4U= -github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= -github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc= -github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= -github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= -github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= -github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= -github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= -github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= -github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.7.1 h1:5TQK59W5E3v0r2duFAb7P95B6hEeOyEnHRa8MjYSMTY= -github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= -go.opencensus.io v0.23.0 h1:gqCw0LfLxScz8irSi8exQc7fyQ0fKQU/qnC/X8+V/1M= -go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= -go.opentelemetry.io/collector v0.50.0 h1:UmSIAwdf6/8xDm+RlfMyDr9qzUkPOviupCQ18SddFm4= -go.opentelemetry.io/collector v0.50.0/go.mod h1:At9TyoUvNAioGllgEvRLOK2MDb6epb4MlHiHQdhBliA= -go.opentelemetry.io/collector/pdata v0.50.0 h1:pXDzXJTze0KqO47BASmKurOIkddk5j4tBLI2cQ94mWg= -go.opentelemetry.io/collector/pdata v0.50.0/go.mod h1:jrnUDnlHCTSKf9H7LYTmldQUmNQmPvilNNG/cKlv8Lc= -go.opentelemetry.io/collector/semconv v0.50.0 h1:DVsidTnfz3ddJlrr354Emc1Vu2rLPxSLToHFYlO0Qp0= -go.opentelemetry.io/collector/semconv v0.50.0/go.mod h1:SxK0rUnUP7YeDakexzbE/vhimTOHwE6m/4aKKd9e27Q= -go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.31.0 h1:li8u9OSMvLau7rMs8bmiL82OazG6MAkwPz2i6eS8TBQ= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.31.0 h1:woM+Mb4d0A+Dxa3rYPenSN5ZeS9qHUvE8rlObiLRXTY= -go.opentelemetry.io/otel v1.6.3 h1:FLOfo8f9JzFVFVyU+MSRJc2HdEAXQgm7pIv2uFKRSZE= -go.opentelemetry.io/otel v1.6.3/go.mod h1:7BgNga5fNlF/iZjG06hM3yofffp0ofKCDwSXx1GC4dI= -go.opentelemetry.io/otel/metric v0.29.0 h1:7unM/I13Dbc1VHw8lTPQ7zfNIgkhcb8BZhujXOS4jKc= -go.opentelemetry.io/otel/metric v0.29.0/go.mod h1:HahKFp1OC1RNTsuO/HNMBHHJR+dmHZ7wLARRgGDwjLQ= -go.opentelemetry.io/otel/sdk v1.6.3 h1:prSHYdwCQOX5DrsEzxowH3nLhoAzEBdZhvrR79scfLs= -go.opentelemetry.io/otel/trace v1.6.3 h1:IqN4L+5b0mPNjdXIiZ90Ni4Bl5BRkDQywePLWemd9bc= -go.opentelemetry.io/otel/trace v1.6.3/go.mod h1:GNJQusJlUgZl9/TQBPKU/Y/ty+0iVB5fjhKeJGZPGFs= -go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= -go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= -go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE= -go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= -go.uber.org/goleak v1.1.11 h1:wy28qYRKZgnJTxGxvye5/wgWr1EKjmUDGYox5mGlRlI= -go.uber.org/goleak v1.1.11/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= -go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= -go.uber.org/multierr v1.8.0 h1:dg6GjLku4EH+249NNmoIciG9N/jURbDG+pFlTkhzIC8= -go.uber.org/multierr v1.8.0/go.mod h1:7EAYxJLBy9rStEaz58O2t4Uvip6FSURkq8/ppBp95ak= -go.uber.org/zap v1.21.0 h1:WefMeulhovoZ2sYXz7st6K0sLj7bBhpiFaud4r4zST8= -go.uber.org/zap v1.21.0/go.mod h1:wjWOCqI0f2ZZrJF/UufIOkiC8ii6tm1iqIsLo76RfJw= -golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= -golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= -golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= -golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= -golang.org/x/net v0.0.0-20220225172249-27dd8689420f h1:oA4XRj0qtSt8Yo1Zms0CUlsT3KG69V2UGQWPBxujDmc= -golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= -golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= -golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190129075346-302c3dd5f1cc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220412211240-33da011f77ad h1:ntjMns5wyP/fN65tdBD4g8J5w8n015+iIIs9rtjXkY0= -golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.1-0.20181227161524-e6919f6577db/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= -golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= -golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= -golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= -golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= -golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= -google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= -google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= -google.golang.org/genproto v0.0.0-20190404172233-64821d5d2107/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= -google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= -google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa h1:I0YcKz0I7OAhddo7ya8kMnvprhcWM045PmkBdMO9zN0= -google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/grpc v1.14.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= -google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= -google.golang.org/grpc v1.22.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= -google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= -google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= -google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= -google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0= -google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= -google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= -google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= -google.golang.org/grpc v1.46.0 h1:oCjezcn6g6A75TGoKYBPgKmVBLexhYLM6MebdrPApP8= -google.golang.org/grpc v1.46.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= -google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= -google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= -google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= -google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= -google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= -google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= -google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= -google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.28.0 h1:w43yiav+6bVFTBQFZX0r7ipe9JQ1QsbMgHwbBziscLw= -google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= -gopkg.in/asn1-ber.v1 v1.0.0-20181015200546-f715ec2f112d/go.mod h1:cuepJuh7vyXfUyUwEgHQXw849cJrilpS5NeIjOWESAw= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= -gopkg.in/square/go-jose.v2 v2.3.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= -gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= -gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= -gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo= -gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= diff --git a/exporter/newrelicexporter/metrics.go b/exporter/newrelicexporter/metrics.go deleted file mode 100644 index 6071ac290d4c..000000000000 --- a/exporter/newrelicexporter/metrics.go +++ /dev/null @@ -1,257 +0,0 @@ -// 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 newrelicexporter // import "github.com/open-telemetry/opentelemetry-collector-contrib/exporter/newrelicexporter" - -import ( - "context" - "strconv" - "strings" - "time" - - "go.opencensus.io/stats" - "go.opencensus.io/stats/view" - "go.opencensus.io/tag" - "go.opentelemetry.io/collector/pdata/pcommon" - "go.opentelemetry.io/collector/pdata/pmetric" - "go.uber.org/multierr" - "google.golang.org/grpc/codes" - "google.golang.org/grpc/metadata" -) - -var ( - tagGrpcStatusCode, _ = tag.NewKey("grpc_response_code") - tagHTTPStatusCode, _ = tag.NewKey("http_status_code") - tagRequestUserAgent, _ = tag.NewKey("user_agent") - tagAPIKey, _ = tag.NewKey("api_key") - tagDataType, _ = tag.NewKey("data_type") - tagMetricType, _ = tag.NewKey("metric_type") - tagMetricTemporality, _ = tag.NewKey("metric_temporality") - tagHasSpanEvents, _ = tag.NewKey("has_span_events") - tagHasSpanLinks, _ = tag.NewKey("has_span_links") - tagAttributeLocation, _ = tag.NewKey("attribute_location") - tagAttributeValueType, _ = tag.NewKey("attribute_type") - tagKeys = []tag.Key{tagGrpcStatusCode, tagHTTPStatusCode, tagRequestUserAgent, tagAPIKey, tagDataType} - metricMetadataTagKeys = []tag.Key{tagGrpcStatusCode, tagHTTPStatusCode, tagRequestUserAgent, tagAPIKey, tagDataType, tagMetricType, tagMetricTemporality} - spanMetadataTagKeys = []tag.Key{tagGrpcStatusCode, tagHTTPStatusCode, tagRequestUserAgent, tagAPIKey, tagDataType, tagHasSpanEvents, tagHasSpanLinks} - attributeMetadataTagKeys = []tag.Key{tagGrpcStatusCode, tagHTTPStatusCode, tagRequestUserAgent, tagAPIKey, tagDataType, tagAttributeLocation, tagAttributeValueType} - - statRequestCount = stats.Int64("newrelicexporter_request_count", "Number of requests processed", stats.UnitDimensionless) - statInputDatapointCount = stats.Int64("newrelicexporter_input_datapoint_count", "Number of data points received by the exporter.", stats.UnitDimensionless) - statOutputDatapointCount = stats.Int64("newrelicexporter_output_datapoint_count", "Number of data points sent to the HTTP API", stats.UnitDimensionless) - statExporterTime = stats.Int64("newrelicexporter_exporter_time", "Wall clock time (milliseconds) spent in the exporter", stats.UnitMilliseconds) - statExternalTime = stats.Int64("newrelicexporter_external_time", "Wall clock time (milliseconds) spent sending data to the HTTP API", stats.UnitMilliseconds) - statMetricMetadata = stats.Int64("newrelicexporter_metric_metadata_count", "Number of metrics processed", stats.UnitDimensionless) - statSpanMetadata = stats.Int64("newrelicexporter_span_metadata_count", "Number of spans processed", stats.UnitDimensionless) - statAttributeMetadata = stats.Int64("newrelicexporter_attribute_metadata_count", "Number of attributes processed", stats.UnitDimensionless) -) - -const EuKeyPrefix = "eu01xx" - -// MetricViews return metric views for Kafka receiver. -func MetricViews() []*view.View { - return []*view.View{ - buildView(tagKeys, statRequestCount, view.Sum()), - { - Name: "newrelicexporter_input_datapoint_count_notag", - Measure: statInputDatapointCount, - Description: statInputDatapointCount.Description(), - TagKeys: []tag.Key{}, - Aggregation: view.Sum(), - }, - buildView(tagKeys, statOutputDatapointCount, view.Sum()), - { - Name: "newrelicexporter_output_datapoint_count_notag", - Measure: statOutputDatapointCount, - Description: statOutputDatapointCount.Description(), - TagKeys: []tag.Key{}, - Aggregation: view.Sum(), - }, - buildView(tagKeys, statExporterTime, view.Sum()), - buildView(tagKeys, statExternalTime, view.Sum()), - buildView(metricMetadataTagKeys, statMetricMetadata, view.Sum()), - buildView(spanMetadataTagKeys, statSpanMetadata, view.Sum()), - buildView(attributeMetadataTagKeys, statAttributeMetadata, view.Sum()), - } -} - -func buildView(tagKeys []tag.Key, m stats.Measure, a *view.Aggregation) *view.View { - return &view.View{ - Name: m.Name(), - Measure: m, - Description: m.Description(), - TagKeys: tagKeys, - Aggregation: a, - } -} - -type metricStatsKey struct { - MetricType pmetric.MetricDataType - MetricTemporality pmetric.MetricAggregationTemporality -} - -type spanStatsKey struct { - hasEvents bool - hasLinks bool -} - -type attributeLocation int - -const ( - attributeLocationResource attributeLocation = iota - attributeLocationSpan - attributeLocationSpanEvent - attributeLocationLog -) - -func (al attributeLocation) String() string { - switch al { - case attributeLocationResource: - return "resource" - case attributeLocationSpan: - return "span" - case attributeLocationSpanEvent: - return "span_event" - case attributeLocationLog: - return "log" - } - return "" -} - -type attributeStatsKey struct { - location attributeLocation - attributeType pcommon.ValueType -} - -type exportMetadata struct { - // Metric tags - grpcResponseCode codes.Code // The gRPC response code - httpStatusCode int // The HTTP response status code form the HTTP API - apiKey string // The API key from the request - userAgent string // The User-Agent from the request - dataType string // The type of data being recorded - - // Metric values - dataInputCount int // Number of resource spans in the request - dataOutputCount int // Number of spans sent to the trace API - exporterTime time.Duration // Total time spent in the newrelic exporter - externalDuration time.Duration // Time spent sending to the trace API - metricMetadataCount map[metricStatsKey]int // Number of metrics by type and temporality - spanMetadataCount map[spanStatsKey]int // Number of spans by whether or not they have events or links - attributeMetadataCount map[attributeStatsKey]int // Number of attributes by location and type -} - -func newTraceMetadata(ctx context.Context) exportMetadata { - return initMetadata(ctx, "trace") -} - -func newLogMetadata(ctx context.Context) exportMetadata { - return initMetadata(ctx, "log") -} - -func newMetricMetadata(ctx context.Context) exportMetadata { - return initMetadata(ctx, "metric") -} - -func initMetadata(ctx context.Context, dataType string) exportMetadata { - userAgent := "not_present" - if md, ctxOk := metadata.FromIncomingContext(ctx); ctxOk { - if values, headerOk := md["user-agent"]; headerOk { - userAgent = values[0] - } - } - - return exportMetadata{ - userAgent: userAgent, - apiKey: "not_present", - dataType: dataType, - metricMetadataCount: make(map[metricStatsKey]int, 8*3 /* 8 metric types by 3 temporarilities */), - spanMetadataCount: make(map[spanStatsKey]int, 2*2 /* combinations of the 2 bool key values */), - attributeMetadataCount: make(map[attributeStatsKey]int, 3*7 /* spans can have 7 value types in 4 different locations */), - } -} - -func (d exportMetadata) recordMetrics(ctx context.Context) error { - tags := []tag.Mutator{ - tag.Insert(tagGrpcStatusCode, d.grpcResponseCode.String()), - tag.Insert(tagHTTPStatusCode, strconv.Itoa(d.httpStatusCode)), - tag.Insert(tagRequestUserAgent, d.userAgent), - tag.Insert(tagAPIKey, d.apiKey), - tag.Insert(tagDataType, d.dataType), - } - - var errs error - errs = multierr.Append(errs, stats.RecordWithTags(ctx, tags, - statRequestCount.M(1), - statInputDatapointCount.M(int64(d.dataInputCount)), - statOutputDatapointCount.M(int64(d.dataOutputCount)), - statExporterTime.M(d.exporterTime.Milliseconds()), - statExternalTime.M(d.externalDuration.Milliseconds()), - )) - - if len(d.metricMetadataCount) > 0 { - metricMetadataTagMutators := make([]tag.Mutator, len(tags)+2) - copy(metricMetadataTagMutators, tags) - for k, v := range d.metricMetadataCount { - metricTypeTag := tag.Insert(tagMetricType, k.MetricType.String()) - metricMetadataTagMutators[len(metricMetadataTagMutators)-2] = metricTypeTag - - temporalityTag := tag.Insert(tagMetricTemporality, k.MetricTemporality.String()) - metricMetadataTagMutators[len(metricMetadataTagMutators)-1] = temporalityTag - - errs = multierr.Append(errs, stats.RecordWithTags(ctx, metricMetadataTagMutators, statMetricMetadata.M(int64(v)))) - } - } - - if len(d.spanMetadataCount) > 0 { - spanMetadataTagMutators := make([]tag.Mutator, len(tags)+2) - copy(spanMetadataTagMutators, tags) - for k, v := range d.spanMetadataCount { - hasSpanEventsTag := tag.Insert(tagHasSpanEvents, strconv.FormatBool(k.hasEvents)) - spanMetadataTagMutators[len(spanMetadataTagMutators)-2] = hasSpanEventsTag - - hasSpanLinksTag := tag.Insert(tagHasSpanLinks, strconv.FormatBool(k.hasLinks)) - spanMetadataTagMutators[len(spanMetadataTagMutators)-1] = hasSpanLinksTag - - errs = multierr.Append(errs, stats.RecordWithTags(ctx, spanMetadataTagMutators, statSpanMetadata.M(int64(v)))) - } - } - - if len(d.attributeMetadataCount) > 0 { - attributeMetadataMutators := make([]tag.Mutator, len(tags)+2) - copy(attributeMetadataMutators, tags) - for k, v := range d.attributeMetadataCount { - locationTag := tag.Insert(tagAttributeLocation, k.location.String()) - attributeMetadataMutators[len(attributeMetadataMutators)-2] = locationTag - - typeTag := tag.Insert(tagAttributeValueType, k.attributeType.String()) - attributeMetadataMutators[len(attributeMetadataMutators)-1] = typeTag - - errs = multierr.Append(errs, stats.RecordWithTags(ctx, attributeMetadataMutators, statAttributeMetadata.M(int64(v)))) - } - } - - return errs -} - -func sanitizeAPIKeyForLogging(apiKey string) string { - if len(apiKey) <= 8 { - return apiKey - } - end := 8 - if strings.HasPrefix(apiKey, EuKeyPrefix) { - end += len(EuKeyPrefix) - } - return apiKey[:end] -} diff --git a/exporter/newrelicexporter/metrics_test.go b/exporter/newrelicexporter/metrics_test.go deleted file mode 100644 index 11d88ea68fec..000000000000 --- a/exporter/newrelicexporter/metrics_test.go +++ /dev/null @@ -1,429 +0,0 @@ -// 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 newrelicexporter - -import ( - "context" - "strings" - "testing" - - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - "go.opencensus.io/stats" - "go.opencensus.io/stats/view" - "go.opencensus.io/tag" - "go.opentelemetry.io/collector/pdata/pcommon" - "go.opentelemetry.io/collector/pdata/pmetric" - "google.golang.org/grpc/codes" - "google.golang.org/grpc/metadata" -) - -func TestMetricViews(t *testing.T) { - metricViews := MetricViews() - - assert.True(t, len(metricViews) > 0) - for _, curView := range metricViews { - assert.True(t, strings.HasPrefix(curView.Name, "newrelicexporter_")) - assert.NotNil(t, curView.Aggregation) - assert.NotNil(t, curView.Description) - if curView.Name == "newrelicexporter_metric_metadata_count" { - assert.Equal(t, metricMetadataTagKeys, curView.TagKeys) - } else if curView.Name == "newrelicexporter_span_metadata_count" { - assert.Equal(t, spanMetadataTagKeys, curView.TagKeys) - } else if curView.Name == "newrelicexporter_attribute_metadata_count" { - assert.Equal(t, attributeMetadataTagKeys, curView.TagKeys) - } else if strings.HasSuffix(curView.Name, "_notag") { - assert.Equal(t, []tag.Key{}, curView.TagKeys) - } else { - assert.Equal(t, tagKeys, curView.TagKeys) - } - assert.NotNil(t, curView.Aggregation) - } -} - -func TestRecordMetrics(t *testing.T) { - view.Unregister(MetricViews()...) - if err := view.Register(MetricViews()...); err != nil { - t.Fail() - } - - details := []exportMetadata{ - // A request that completes normally - { - grpcResponseCode: codes.OK, - httpStatusCode: 200, - apiKey: "shhh", - userAgent: "secret agent", - dataType: "data", - dataInputCount: 2, - exporterTime: 100, - dataOutputCount: 20, - externalDuration: 50, - }, - // A request that receives 403 status code from the HTTP API - { - grpcResponseCode: codes.Unauthenticated, - httpStatusCode: 403, - apiKey: "shhh", - userAgent: "secret agent", - dataType: "data", - dataInputCount: 2, - exporterTime: 100, - dataOutputCount: 20, - externalDuration: 50, - }, - // A request experiences a url.Error while sending to the HTTP API - { - grpcResponseCode: codes.DataLoss, - httpStatusCode: 0, - apiKey: "shhh", - userAgent: "secret agent", - dataType: "data", - dataInputCount: 2, - exporterTime: 100, - dataOutputCount: 20, - externalDuration: 50, - }, - } - - for _, traceDetails := range details { - if err := traceDetails.recordMetrics(context.TODO()); err != nil { - t.Fail() - } - } - - measurements := []stats.Measure{ - statRequestCount, - statOutputDatapointCount, - statExporterTime, - statExternalTime, - } - - for _, measurement := range measurements { - rows, err := view.RetrieveData(measurement.Name()) - if err != nil { - t.Fail() - } - // Check that each measurement has a number of rows corresponding to the tag set produced by the interactions - assert.Equal(t, len(details), len(rows)) - for _, row := range rows { - // Confirm each row has data and has the required tag keys - assert.True(t, row.Data != nil) - assert.Equal(t, len(tagKeys), len(row.Tags)) - for _, rowTag := range row.Tags { - assert.Contains(t, tagKeys, rowTag.Key) - } - } - } -} - -func TestRecordMetricMetadata(t *testing.T) { - view.Unregister(MetricViews()...) - if err := view.Register(MetricViews()...); err != nil { - t.Fail() - } - - detail := exportMetadata{ - grpcResponseCode: codes.OK, - httpStatusCode: 200, - apiKey: "shhh", - userAgent: "secret agent", - dataType: "metric", - dataInputCount: 2, - exporterTime: 100, - dataOutputCount: 20, - externalDuration: 50, - metricMetadataCount: map[metricStatsKey]int{ - {MetricType: pmetric.MetricDataTypeSummary}: 1, - {MetricType: pmetric.MetricDataTypeHistogram}: 1, - {MetricType: pmetric.MetricDataTypeSum, MetricTemporality: pmetric.MetricAggregationTemporalityDelta}: 2, - {MetricType: pmetric.MetricDataTypeSum, MetricTemporality: pmetric.MetricAggregationTemporalityCumulative}: 3, - }, - } - - if err := detail.recordMetrics(context.TODO()); err != nil { - t.Fail() - } - - rows, err := view.RetrieveData(statMetricMetadata.Name()) - if err != nil { - t.Fail() - } - // Check that the measurement has the right number of results recorded - assert.Equal(t, len(detail.metricMetadataCount), len(rows)) - for _, row := range rows { - // Confirm each row has data and has the required tag keys - assert.True(t, row.Data != nil) - assert.Equal(t, len(metricMetadataTagKeys), len(row.Tags)) - for _, rowTag := range row.Tags { - assert.Contains(t, metricMetadataTagKeys, rowTag.Key) - } - } -} - -func TestDoesNotRecordMetricMetadata(t *testing.T) { - view.Unregister(MetricViews()...) - if err := view.Register(MetricViews()...); err != nil { - t.Fail() - } - - detail := exportMetadata{ - grpcResponseCode: codes.OK, - httpStatusCode: 200, - apiKey: "shhh", - userAgent: "secret agent", - dataType: "metric", - dataInputCount: 2, - exporterTime: 100, - dataOutputCount: 20, - externalDuration: 50, - } - - if err := detail.recordMetrics(context.TODO()); err != nil { - t.Fail() - } - - rows, err := view.RetrieveData(statMetricMetadata.Name()) - if err != nil { - t.Fail() - } - // No results should have been recorded - assert.Equal(t, 0, len(rows)) -} - -func TestRecordSpanMetadata(t *testing.T) { - view.Unregister(MetricViews()...) - if err := view.Register(MetricViews()...); err != nil { - t.Fail() - } - - detail := exportMetadata{ - grpcResponseCode: codes.OK, - httpStatusCode: 200, - apiKey: "shhh", - userAgent: "secret agent", - dataType: "metric", - dataInputCount: 2, - exporterTime: 100, - dataOutputCount: 20, - externalDuration: 50, - spanMetadataCount: map[spanStatsKey]int{ - {hasEvents: false, hasLinks: false}: 1, - {hasEvents: true, hasLinks: false}: 1, - {hasEvents: false, hasLinks: true}: 2, - {hasEvents: true, hasLinks: true}: 3, - }, - } - - if err := detail.recordMetrics(context.TODO()); err != nil { - t.Fail() - } - - rows, err := view.RetrieveData(statSpanMetadata.Name()) - if err != nil { - t.Fail() - } - // Check that the measurement has the right number of results recorded - assert.Equal(t, len(detail.spanMetadataCount), len(rows)) - for _, row := range rows { - // Confirm each row has data and has the required tag keys - assert.True(t, row.Data != nil) - assert.Equal(t, len(spanMetadataTagKeys), len(row.Tags)) - for _, rowTag := range row.Tags { - assert.Contains(t, spanMetadataTagKeys, rowTag.Key) - } - } -} - -func TestDoesNotRecordSpanMetadata(t *testing.T) { - view.Unregister(MetricViews()...) - if err := view.Register(MetricViews()...); err != nil { - t.Fail() - } - - detail := exportMetadata{ - grpcResponseCode: codes.OK, - httpStatusCode: 200, - apiKey: "shhh", - userAgent: "secret agent", - dataType: "metric", - dataInputCount: 2, - exporterTime: 100, - dataOutputCount: 20, - externalDuration: 50, - } - - if err := detail.recordMetrics(context.TODO()); err != nil { - t.Fail() - } - - rows, err := view.RetrieveData(statSpanMetadata.Name()) - if err != nil { - t.Fail() - } - // No results should have been recorded - assert.Equal(t, 0, len(rows)) -} - -func TestRecordAttributeMetadata(t *testing.T) { - view.Unregister(MetricViews()...) - if err := view.Register(MetricViews()...); err != nil { - t.Fail() - } - - detail := exportMetadata{ - grpcResponseCode: codes.OK, - httpStatusCode: 200, - apiKey: "shhh", - userAgent: "secret agent", - dataType: "data", - dataInputCount: 2, - exporterTime: 100, - dataOutputCount: 20, - externalDuration: 50, - attributeMetadataCount: map[attributeStatsKey]int{ - {attributeType: pcommon.ValueTypeSlice, location: attributeLocationResource}: 1, - {attributeType: pcommon.ValueTypeBool, location: attributeLocationSpan}: 1, - {attributeType: pcommon.ValueTypeMap, location: attributeLocationSpanEvent}: 1, - {attributeType: pcommon.ValueTypeDouble, location: attributeLocationLog}: 1, - {attributeType: pcommon.ValueTypeInt, location: attributeLocationResource}: 1, - {attributeType: pcommon.ValueTypeEmpty, location: attributeLocationSpan}: 1, - {attributeType: pcommon.ValueTypeString, location: attributeLocationSpanEvent}: 1, - }, - } - - if err := detail.recordMetrics(context.TODO()); err != nil { - t.Fail() - } - - rows, err := view.RetrieveData(statAttributeMetadata.Name()) - if err != nil { - t.Fail() - } - // Check that the measurement has the right number of results recorded - assert.Equal(t, len(detail.attributeMetadataCount), len(rows)) - for _, row := range rows { - // Confirm each row has data and has the required tag keys - assert.True(t, row.Data != nil) - assert.Equal(t, len(attributeMetadataTagKeys), len(row.Tags)) - for _, rowTag := range row.Tags { - assert.Contains(t, attributeMetadataTagKeys, rowTag.Key) - } - } -} - -func TestDoesNotRecordAttributeMetadata(t *testing.T) { - view.Unregister(MetricViews()...) - if err := view.Register(MetricViews()...); err != nil { - t.Fail() - } - - detail := exportMetadata{ - grpcResponseCode: codes.OK, - httpStatusCode: 200, - apiKey: "shhh", - userAgent: "secret agent", - dataType: "metric", - dataInputCount: 2, - exporterTime: 100, - dataOutputCount: 20, - externalDuration: 50, - } - - if err := detail.recordMetrics(context.TODO()); err != nil { - t.Fail() - } - - rows, err := view.RetrieveData(statAttributeMetadata.Name()) - if err != nil { - t.Fail() - } - // No results should have been recorded - assert.Equal(t, 0, len(rows)) -} - -func TestAttributeLocationString(t *testing.T) { - locations := []attributeLocation{ - attributeLocationResource, - attributeLocationSpan, - attributeLocationSpanEvent, - attributeLocationLog, - 99, - } - - expectedStrings := []string{ - "resource", - "span", - "span_event", - "log", - "", - } - - for i := 0; i < len(locations); i++ { - assert.Equal(t, expectedStrings[i], locations[i].String()) - } -} - -func TestSanitizeApiKeyForLogging(t *testing.T) { - assert.Equal(t, "", sanitizeAPIKeyForLogging("")) - assert.Equal(t, "foo", sanitizeAPIKeyForLogging("foo")) - assert.Equal(t, "foobarba", sanitizeAPIKeyForLogging("foobarbazqux")) - assert.Equal(t, "eu01xxfoobarba", sanitizeAPIKeyForLogging("eu01xxfoobarbazqux")) -} - -func TestMetadataHasDefaultValuesSet(t *testing.T) { - m := initMetadata(context.Background(), "testdatatype") - - assert.Equal(t, "not_present", m.userAgent) - assert.Equal(t, "not_present", m.apiKey) - assert.Equal(t, "testdatatype", m.dataType) - assert.NotNil(t, m.metricMetadataCount) - assert.NotNil(t, m.spanMetadataCount) - assert.NotNil(t, m.attributeMetadataCount) -} - -func TestMetadataHasUserAgentWhenAvailable(t *testing.T) { - ctx := metadata.NewIncomingContext(context.Background(), metadata.MD{"user-agent": []string{"testuseragent"}}) - - m := initMetadata(ctx, "testdatatype") - - assert.Equal(t, "testuseragent", m.userAgent) -} - -func TestErrorsAreCombinedIntoSingleError(t *testing.T) { - view.Unregister(MetricViews()...) - if err := view.Register(MetricViews()...); err != nil { - t.Fail() - } - - ctx := metadata.NewIncomingContext(context.Background(), metadata.MD{"user-agent": []string{"testuseragent"}}) - - // Tag values with length > 255 will generate an error when recording metrics - b := make([]byte, 300) - for i := 0; i < 300; i++ { - b[i] = 'a' - } - reallyLongDataType := string(b) - m := initMetadata(ctx, reallyLongDataType) - m.metricMetadataCount[metricStatsKey{}]++ - m.spanMetadataCount[spanStatsKey{}]++ - m.attributeMetadataCount[attributeStatsKey{}]++ - - err := m.recordMetrics(ctx) - - require.Error(t, err) - // The bad tag value should result in 4 errors for each metric and there are 4 metrics - assert.Equal(t, 8, len(strings.Split(err.Error(), ";"))) -} diff --git a/exporter/newrelicexporter/mock_test.go b/exporter/newrelicexporter/mock_test.go deleted file mode 100644 index f1a3e6a5e531..000000000000 --- a/exporter/newrelicexporter/mock_test.go +++ /dev/null @@ -1,129 +0,0 @@ -// 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 newrelicexporter - -import ( - "compress/gzip" - "encoding/json" - "io/ioutil" - "net/http" - "net/http/httptest" -) - -type Batch struct { - Common Common `json:"common"` - Spans []Span `json:"spans"` - Metrics []Metric `json:"metrics"` - Logs []Log `json:"logs"` - XXXUnrecognized []byte `json:"-"` -} - -type Common struct { - Attributes map[string]string `json:"attributes"` - XXXUnrecognized []byte `json:"-"` -} - -type Span struct { - ID string `json:"id"` - TraceID string `json:"trace.id"` - Attributes map[string]interface{} `json:"attributes"` - XXXUnrecognized []byte `json:"-"` -} - -type Metric struct { - Name string `json:"name"` - Type string `json:"type"` - Value interface{} `json:"value"` - Timestamp int64 `json:"timestamp"` - Interval int64 `json:"interval"` - Attributes map[string]interface{} `json:"attributes"` - XXXUnrecognized []byte `json:"-"` -} - -type Log struct { - Message string `json:"message"` - Timestamp int64 `json:"timestamp"` - Attributes map[string]interface{} `json:"attributes"` - XXXUnrecognized []byte `json:"-"` -} - -// Mock caches decompressed request bodies -type Mock struct { - Header http.Header - Batches []Batch - StatusCode int - ResponseHeaders map[string]string -} - -func (c *Mock) Spans() []Span { - var spans []Span - for _, data := range c.Batches { - spans = append(spans, data.Spans...) - } - return spans -} - -func (c *Mock) Metrics() []Metric { - var metrics []Metric - for _, data := range c.Batches { - metrics = append(metrics, data.Metrics...) - } - return metrics -} - -func (c *Mock) Server() *httptest.Server { - return httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - // telemetry sdk gzip compresses json payloads - gz, err := gzip.NewReader(r.Body) - if err != nil { - http.Error(w, err.Error(), http.StatusInternalServerError) - return - } - defer gz.Close() - - contents, err := ioutil.ReadAll(gz) - if err != nil { - http.Error(w, err.Error(), http.StatusInternalServerError) - return - } - - if !json.Valid(contents) { - http.Error(w, "invalid JSON body", http.StatusBadRequest) - return - } - err = c.ParseRequest(contents) - if err != nil { - http.Error(w, err.Error(), http.StatusBadRequest) - return - } - - c.Header = r.Header - - for k, v := range c.ResponseHeaders { - w.Header().Set(k, v) - } - - w.WriteHeader(c.StatusCode) - })) -} - -func (c *Mock) ParseRequest(b []byte) error { - var data []Batch - if err := json.Unmarshal(b, &data); err != nil { - return err - } - c.Batches = append(c.Batches, data...) - return nil -} diff --git a/exporter/newrelicexporter/newrelic.go b/exporter/newrelicexporter/newrelic.go deleted file mode 100644 index 8c79ce3c884e..000000000000 --- a/exporter/newrelicexporter/newrelic.go +++ /dev/null @@ -1,383 +0,0 @@ -// 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 newrelicexporter // import "github.com/open-telemetry/opentelemetry-collector-contrib/exporter/newrelicexporter" - -import ( - "context" - "errors" - "io" - "io/ioutil" - "net/http" - "strings" - "time" - - "github.com/newrelic/newrelic-telemetry-sdk-go/telemetry" - "go.opentelemetry.io/collector/component" - "go.opentelemetry.io/collector/pdata/plog" - "go.opentelemetry.io/collector/pdata/pmetric" - "go.opentelemetry.io/collector/pdata/ptrace" - "go.uber.org/multierr" - "go.uber.org/zap" - "google.golang.org/grpc/metadata" - "google.golang.org/grpc/status" -) - -const ( - product = "NewRelic-OpenTelemetry-Collector" -) - -// exporter exports OpenTelemetry Collector data to New Relic. -type exporter struct { - buildInfo *component.BuildInfo - requestFactory telemetry.RequestFactory - apiKeyHeader string - logger *zap.Logger -} - -type factoryBuilder func(options ...telemetry.ClientOption) (telemetry.RequestFactory, error) -type batchBuilder func() ([]telemetry.Batch, error) - -func clientOptionForAPIKey(apiKey string) telemetry.ClientOption { - if apiKey != "" { - if len(apiKey) < 40 { - return telemetry.WithInsertKey(apiKey) - } - return telemetry.WithLicenseKey(apiKey) - } - return nil -} - -func clientOptions(info *component.BuildInfo, apiKey string, apiKeyHeader string, hostOverride string, insecure bool) []telemetry.ClientOption { - userAgent := product - if info.Version != "" { - userAgent += "/" + info.Version - } - userAgent += " " + info.Command - options := []telemetry.ClientOption{telemetry.WithUserAgent(userAgent)} - if apiKey != "" { - options = append(options, clientOptionForAPIKey(apiKey)) - } else if apiKeyHeader != "" { - options = append(options, telemetry.WithNoDefaultKey()) - } - - if hostOverride != "" { - options = append(options, telemetry.WithEndpoint(hostOverride)) - } - - if insecure { - options = append(options, telemetry.WithInsecure()) - } - return options -} - -func newExporter(l *zap.Logger, buildInfo *component.BuildInfo, nrConfig EndpointConfig, createFactory factoryBuilder) (exporter, error) { - options := clientOptions( - buildInfo, - nrConfig.APIKey, - nrConfig.APIKeyHeader, - nrConfig.HostOverride, - nrConfig.insecure, - ) - f, err := createFactory(options...) - if nil != err { - return exporter{}, err - } - return exporter{ - buildInfo: buildInfo, - requestFactory: f, - apiKeyHeader: strings.ToLower(nrConfig.APIKeyHeader), - logger: l, - }, nil -} - -func (e exporter) extractAPIKeyFromHeader(ctx context.Context) string { - if e.apiKeyHeader == "" { - return "" - } - - // right now, we only support looking up attributes from requests that have gone through the gRPC server - // in that case, it will add the HTTP headers as context metadata - md, ok := metadata.FromIncomingContext(ctx) - if !ok { - return "" - } - - // we have gRPC metadata in the context but does it have our key? - values, ok := md[e.apiKeyHeader] - if !ok { - return "" - } - - return values[0] -} - -func (e exporter) pushTraceData(ctx context.Context, td ptrace.Traces) (outputErr error) { - details := newTraceMetadata(ctx) - details.dataInputCount = td.SpanCount() - builder := func() ([]telemetry.Batch, error) { return e.buildTraceBatch(&details, td) } - return e.export(ctx, &details, builder) -} - -func (e exporter) buildTraceBatch(details *exportMetadata, td ptrace.Traces) ([]telemetry.Batch, error) { - var errs error - - transform := newTransformer(e.logger, e.buildInfo, details) - batches := make([]telemetry.Batch, 0, calcSpanBatches(td)) - - for i := 0; i < td.ResourceSpans().Len(); i++ { - rspans := td.ResourceSpans().At(i) - for j := 0; j < rspans.ScopeSpans().Len(); j++ { - ispans := rspans.ScopeSpans().At(j) - commonAttributes := transform.CommonAttributes(rspans.Resource(), ispans.Scope()) - spanCommon, err := telemetry.NewSpanCommonBlock(telemetry.WithSpanAttributes(commonAttributes)) - if err != nil { - e.logger.Error("Transform of span common attributes failed.", zap.Error(err)) - errs = multierr.Append(errs, err) - continue - } - spans := make([]telemetry.Span, 0, ispans.Spans().Len()) - for k := 0; k < ispans.Spans().Len(); k++ { - span := ispans.Spans().At(k) - nrSpan, err := transform.Span(span) - if err != nil { - e.logger.Debug("Transform of span failed.", zap.Error(err)) - errs = multierr.Append(errs, err) - continue - } - - details.dataOutputCount++ - spans = append(spans, nrSpan) - } - batches = append(batches, telemetry.Batch{spanCommon, telemetry.NewSpanGroup(spans)}) - } - } - - return batches, errs -} - -func calcSpanBatches(td ptrace.Traces) int { - rss := td.ResourceSpans() - batchCount := 0 - for i := 0; i < rss.Len(); i++ { - batchCount += rss.At(i).ScopeSpans().Len() - } - return batchCount -} - -func (e exporter) pushLogData(ctx context.Context, ld plog.Logs) (outputErr error) { - details := newLogMetadata(ctx) - details.dataInputCount = ld.LogRecordCount() - builder := func() ([]telemetry.Batch, error) { return e.buildLogBatch(&details, ld) } - return e.export(ctx, &details, builder) -} - -func (e exporter) buildLogBatch(details *exportMetadata, ld plog.Logs) ([]telemetry.Batch, error) { - var errs error - - transform := newTransformer(e.logger, e.buildInfo, details) - batches := make([]telemetry.Batch, 0, calcLogBatches(ld)) - - for i := 0; i < ld.ResourceLogs().Len(); i++ { - rlogs := ld.ResourceLogs().At(i) - for j := 0; j < rlogs.ScopeLogs().Len(); j++ { - ilogs := rlogs.ScopeLogs().At(j) - commonAttributes := transform.CommonAttributes(rlogs.Resource(), ilogs.Scope()) - logCommon, err := telemetry.NewLogCommonBlock(telemetry.WithLogAttributes(commonAttributes)) - if err != nil { - e.logger.Error("Transform of log common attributes failed.", zap.Error(err)) - errs = multierr.Append(errs, err) - continue - } - logs := make([]telemetry.Log, 0, ilogs.LogRecords().Len()) - for k := 0; k < ilogs.LogRecords().Len(); k++ { - log := ilogs.LogRecords().At(k) - nrLog, err := transform.Log(log) - if err != nil { - e.logger.Error("Transform of log failed.", zap.Error(err)) - errs = multierr.Append(errs, err) - continue - } - - details.dataOutputCount++ - logs = append(logs, nrLog) - } - batches = append(batches, telemetry.Batch{logCommon, telemetry.NewLogGroup(logs)}) - } - } - - return batches, errs -} - -func calcLogBatches(ld plog.Logs) int { - rss := ld.ResourceLogs() - batchCount := 0 - for i := 0; i < rss.Len(); i++ { - batchCount += rss.At(i).ScopeLogs().Len() - } - return batchCount -} - -func (e exporter) pushMetricData(ctx context.Context, md pmetric.Metrics) (outputErr error) { - details := newMetricMetadata(ctx) - details.dataInputCount = md.DataPointCount() - builder := func() ([]telemetry.Batch, error) { return e.buildMetricBatch(&details, md) } - return e.export(ctx, &details, builder) -} - -func (e exporter) buildMetricBatch(details *exportMetadata, md pmetric.Metrics) ([]telemetry.Batch, error) { - var errs error - - transform := newTransformer(e.logger, e.buildInfo, details) - batches := make([]telemetry.Batch, 0, calcMetricBatches(md)) - - for i := 0; i < md.ResourceMetrics().Len(); i++ { - rmetrics := md.ResourceMetrics().At(i) - for j := 0; j < rmetrics.ScopeMetrics().Len(); j++ { - imetrics := rmetrics.ScopeMetrics().At(j) - commonAttributes := transform.CommonAttributes(rmetrics.Resource(), imetrics.Scope()) - metricCommon, err := telemetry.NewMetricCommonBlock(telemetry.WithMetricAttributes(commonAttributes)) - if err != nil { - e.logger.Error("Transform of metric common attributes failed.", zap.Error(err)) - errs = multierr.Append(errs, err) - continue - } - metricSlices := make([][]telemetry.Metric, 0, imetrics.Metrics().Len()) - for k := 0; k < imetrics.Metrics().Len(); k++ { - metric := imetrics.Metrics().At(k) - nrMetrics, err := transform.Metric(metric) - if err != nil { - { - var unsupportedErr *errUnsupportedMetricType - if ok := errors.As(err, &unsupportedErr); ok { - // Treat invalid metrics as a success - details.dataOutputCount += unsupportedErr.numDataPoints - } - } - e.logger.Debug("Transform of metric failed.", zap.Error(err)) - errs = multierr.Append(errs, err) - continue - } - details.dataOutputCount += len(nrMetrics) - metricSlices = append(metricSlices, nrMetrics) - } - metrics := combineMetricSlices(metricSlices) - batches = append(batches, telemetry.Batch{metricCommon, telemetry.NewMetricGroup(metrics)}) - } - } - - return batches, errs -} - -func calcMetricBatches(md pmetric.Metrics) int { - rss := md.ResourceMetrics() - batchCount := 0 - for i := 0; i < rss.Len(); i++ { - batchCount += rss.At(i).ScopeMetrics().Len() - } - return batchCount -} - -func combineMetricSlices(groups [][]telemetry.Metric) []telemetry.Metric { - var totalLen int - for _, group := range groups { - totalLen += len(group) - } - metrics := make([]telemetry.Metric, totalLen) - var i int - for _, group := range groups { - i += copy(metrics[i:], group) - } - return metrics -} - -func (e exporter) export( - ctx context.Context, - details *exportMetadata, - buildBatches batchBuilder, -) (outputErr error) { - startTime := time.Now() - apiKey := e.extractAPIKeyFromHeader(ctx) - defer func() { - details.apiKey = sanitizeAPIKeyForLogging(apiKey) - details.exporterTime = time.Since(startTime) - details.grpcResponseCode = status.Code(outputErr) - err := details.recordMetrics(ctx) - if err != nil { - e.logger.Error("An error occurred recording metrics.", zap.Error(err)) - } - }() - - batches, mapEntryErrors := buildBatches() - - var options []telemetry.ClientOption - if option := clientOptionForAPIKey(apiKey); option != nil { - options = append(options, option) - } - - req, err := e.requestFactory.BuildRequest(ctx, batches, options...) - if err != nil { - e.logger.Error("Failed to build data map", zap.Error(err)) - return err - } - - if err := e.doRequest(details, req); err != nil { - return err - } - - return mapEntryErrors -} - -func (e exporter) doRequest(details *exportMetadata, req *http.Request) error { - startTime := time.Now() - defer func() { details.externalDuration = time.Since(startTime) }() - - // Execute the http request and handle the response - response, err := http.DefaultClient.Do(req) - if err != nil { - // If the context cancellation caused the error, we don't want to log that error. - // Only log an error when the context is still active - if ctxErr := req.Context().Err(); ctxErr == nil { - e.logger.Error("Error making HTTP request.", zap.Error(err)) - } - err := &urlError{err: err} - return err.Wrap() - } - defer response.Body.Close() - io.Copy(ioutil.Discard, response.Body) - details.httpStatusCode = response.StatusCode - - // Check if the http payload has been accepted, if not record an error - if response.StatusCode != http.StatusAccepted { - // Log the error at an appropriate level based on the status code - if response.StatusCode >= 500 { - // The data has been lost, but it is due to a server side error - e.logger.Warn("Server HTTP error", zap.String("Status", response.Status), zap.Stringer("Url", req.URL)) - } else if response.StatusCode == http.StatusForbidden { - // The data has been lost, but it is due to an invalid api key - e.logger.Debug("HTTP Forbidden response", zap.String("Status", response.Status), zap.Stringer("Url", req.URL)) - } else if response.StatusCode == http.StatusTooManyRequests { - // The data has been lost, but it is due to rate limiting - e.logger.Debug("HTTP Too Many Requests", zap.String("Status", response.Status), zap.Stringer("Url", req.URL)) - } else { - // The data has been lost due to an error in our payload - details.dataOutputCount = 0 - e.logger.Error("Client HTTP error.", zap.String("Status", response.Status), zap.Stringer("Url", req.URL)) - } - - err := newHTTPError(response) - return err.Wrap() - } - return nil -} diff --git a/exporter/newrelicexporter/newrelic_test.go b/exporter/newrelicexporter/newrelic_test.go deleted file mode 100644 index 3b10447326f3..000000000000 --- a/exporter/newrelicexporter/newrelic_test.go +++ /dev/null @@ -1,939 +0,0 @@ -// 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 newrelicexporter - -import ( - "context" - "errors" - "fmt" - "math" - "net/http" - "net/url" - "strings" - "testing" - "time" - - commonpb "github.com/census-instrumentation/opencensus-proto/gen-go/agent/common/v1" - agentmetricspb "github.com/census-instrumentation/opencensus-proto/gen-go/agent/metrics/v1" - metricspb "github.com/census-instrumentation/opencensus-proto/gen-go/metrics/v1" - resourcepb "github.com/census-instrumentation/opencensus-proto/gen-go/resource/v1" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - "go.opencensus.io/stats/view" - "go.opentelemetry.io/collector/component/componenttest" - "go.opentelemetry.io/collector/exporter/exporterhelper" - "go.opentelemetry.io/collector/pdata/pcommon" - "go.opentelemetry.io/collector/pdata/plog" - "go.opentelemetry.io/collector/pdata/pmetric" - "go.opentelemetry.io/collector/pdata/ptrace" - "google.golang.org/grpc/metadata" - "google.golang.org/protobuf/types/known/timestamppb" - - internaldata "github.com/open-telemetry/opentelemetry-collector-contrib/pkg/translator/opencensus" -) - -const ( - testCollectorName = "otelcol" - testCollectorVersion = "latest" -) - -type mockConfig struct { - useAPIKeyHeader bool - serverURL string - statusCode int - responseHeaders map[string]string -} - -func runTraceMock(initialContext context.Context, ptrace ptrace.Traces, cfg mockConfig) (*Mock, error) { - ctx, cancel := context.WithCancel(initialContext) - defer cancel() - - m := &Mock{ - Batches: make([]Batch, 0, 1), - StatusCode: 202, - } - - if cfg.statusCode > 0 { - m.StatusCode = cfg.statusCode - } - - if cfg.responseHeaders != nil { - m.ResponseHeaders = cfg.responseHeaders - } - - srv := m.Server() - defer srv.Close() - - f := NewFactory() - c := f.CreateDefaultConfig().(*Config) - urlString := srv.URL - if cfg.serverURL != "" { - urlString = cfg.serverURL - } - u, _ := url.Parse(urlString) - - if cfg.useAPIKeyHeader { - c.TracesConfig.APIKeyHeader = "api-key" - } else { - c.TracesConfig.APIKey = "NRII-1" - } - c.TracesConfig.insecure, c.TracesConfig.HostOverride = true, u.Host - exp, err := f.CreateTracesExporter(context.Background(), componenttest.NewNopExporterCreateSettings(), c) - if err != nil { - return m, err - } - if err := exp.ConsumeTraces(ctx, ptrace); err != nil { - return m, err - } - if err := exp.Shutdown(ctx); err != nil { - return m, err - } - return m, nil -} - -func runMetricMock(initialContext context.Context, pmetrics pmetric.Metrics, cfg mockConfig) (*Mock, error) { - ctx, cancel := context.WithCancel(initialContext) - defer cancel() - - m := &Mock{ - Batches: make([]Batch, 0, 1), - StatusCode: 202, - } - - if cfg.statusCode > 0 { - m.StatusCode = cfg.statusCode - } - - srv := m.Server() - defer srv.Close() - - f := NewFactory() - c := f.CreateDefaultConfig().(*Config) - urlString := srv.URL - if cfg.serverURL != "" { - urlString = cfg.serverURL - } - u, _ := url.Parse(urlString) - - if cfg.useAPIKeyHeader { - c.MetricsConfig.APIKeyHeader = "api-key" - } else { - c.MetricsConfig.APIKey = "NRII-1" - } - c.MetricsConfig.insecure, c.MetricsConfig.HostOverride = true, u.Host - exp, err := f.CreateMetricsExporter(context.Background(), componenttest.NewNopExporterCreateSettings(), c) - if err != nil { - return m, err - } - if err := exp.ConsumeMetrics(ctx, pmetrics); err != nil { - return m, err - } - if err := exp.Shutdown(ctx); err != nil { - return m, err - } - return m, nil -} - -func runLogMock(initialContext context.Context, plogs plog.Logs, cfg mockConfig) (*Mock, error) { - ctx, cancel := context.WithCancel(initialContext) - defer cancel() - - m := &Mock{ - Batches: make([]Batch, 0, 1), - StatusCode: 202, - } - - if cfg.statusCode > 0 { - m.StatusCode = cfg.statusCode - } - - srv := m.Server() - defer srv.Close() - - f := NewFactory() - c := f.CreateDefaultConfig().(*Config) - urlString := srv.URL - if cfg.serverURL != "" { - urlString = cfg.serverURL - } - u, _ := url.Parse(urlString) - - if cfg.useAPIKeyHeader { - c.LogsConfig.APIKeyHeader = "api-key" - } else { - c.LogsConfig.APIKey = "NRII-1" - } - c.LogsConfig.insecure, c.LogsConfig.HostOverride = true, u.Host - exp, err := f.CreateLogsExporter(context.Background(), componenttest.NewNopExporterCreateSettings(), c) - if err != nil { - return m, err - } - if err := exp.ConsumeLogs(ctx, plogs); err != nil { - return m, err - } - if err := exp.Shutdown(ctx); err != nil { - return m, err - } - return m, nil -} - -func testTraceData(t *testing.T, expected []Batch, td ptrace.Traces, apiKey string) { - ctx := context.Background() - useAPIKeyHeader := apiKey != "" - if useAPIKeyHeader { - ctx = metadata.NewIncomingContext(ctx, metadata.MD{"api-key": []string{apiKey}}) - } - - m, err := runTraceMock(ctx, td, mockConfig{useAPIKeyHeader: useAPIKeyHeader}) - require.NoError(t, err) - assert.Equal(t, expected, m.Batches) - if !useAPIKeyHeader { - assert.Equal(t, []string{"NRII-1"}, m.Header[http.CanonicalHeaderKey("api-key")]) - } else if len(apiKey) < 40 { - assert.Equal(t, []string{apiKey}, m.Header[http.CanonicalHeaderKey("api-key")]) - } else { - assert.Equal(t, []string{apiKey}, m.Header[http.CanonicalHeaderKey("x-license-key")]) - } -} - -func testMetricData(t *testing.T, expected []Batch, md *agentmetricspb.ExportMetricsServiceRequest, apiKey string) { - ctx := context.Background() - useAPIKeyHeader := apiKey != "" - if useAPIKeyHeader { - ctx = metadata.NewIncomingContext(ctx, metadata.MD{"api-key": []string{apiKey}}) - } - - m, err := runMetricMock(ctx, internaldata.OCToMetrics(md.Node, md.Resource, md.Metrics), mockConfig{useAPIKeyHeader: useAPIKeyHeader}) - require.NoError(t, err) - assert.Equal(t, expected, m.Batches) -} - -func testLogData(t *testing.T, expected []Batch, logs plog.Logs, apiKey string) { - ctx := context.Background() - useAPIKeyHeader := apiKey != "" - if useAPIKeyHeader { - ctx = metadata.NewIncomingContext(ctx, metadata.MD{"api-key": []string{apiKey}}) - } - - l, err := runLogMock(ctx, logs, mockConfig{useAPIKeyHeader: useAPIKeyHeader}) - require.NoError(t, err) - assert.Equal(t, expected, l.Batches) -} - -func TestExportTraceWithBadURL(t *testing.T) { - _, err := runTraceMock(context.Background(), newTestTraces(), mockConfig{serverURL: "http://badurl"}) - require.Error(t, err) -} - -func TestExportTraceWithErrorStatusCode(t *testing.T) { - _, err := runTraceMock(context.Background(), newTestTraces(), mockConfig{statusCode: 500}) - require.Error(t, err) -} - -func TestExportTraceWith429StatusCodeAndRetryAfter(t *testing.T) { - expected := exporterhelper.NewThrottleRetry( - fmt.Errorf("new relic HTTP call failed. Status Code: 429"), - time.Duration(10)*time.Second) - - _, err := runTraceMock(context.Background(), newTestTraces(), mockConfig{statusCode: 429, responseHeaders: map[string]string{"Retry-After": "10"}}) - - actual := errors.Unwrap(err) - - assert.EqualValues(t, expected, actual) -} - -func TestExportTraceWithNot202StatusCode(t *testing.T) { - { - _, err := runTraceMock(context.Background(), newTestTraces(), mockConfig{statusCode: 403}) - require.Error(t, err) - } - { - _, err := runTraceMock(context.Background(), newTestTraces(), mockConfig{statusCode: 429}) - require.Error(t, err) - } -} - -func TestExportTraceWithBadPayload(t *testing.T) { - _, err := runTraceMock(context.Background(), newTestTraces(), mockConfig{statusCode: 400}) - require.Error(t, err) -} - -func TestExportTraceWithInvalidMetadata(t *testing.T) { - // TODO: Newrelic owners to investigate why passing valid data "newTestTraces()" does not return error. - td := ptrace.NewTraces() - s := td.ResourceSpans().AppendEmpty().ScopeSpans().AppendEmpty().Spans().AppendEmpty() - s.SetName("a") - s.SetSpanID(pcommon.NewSpanID([8]byte{0, 0, 0, 0, 0, 0, 0, 1})) - - _, err := runTraceMock(context.Background(), td, mockConfig{useAPIKeyHeader: true}) - require.Error(t, err) -} - -func TestExportTraceWithNoAPIKeyInMetadata(t *testing.T) { - // TODO: Newrelic owners to investigate why passing valid data "newTestTraces()" does not return error. - td := ptrace.NewTraces() - s := td.ResourceSpans().AppendEmpty().ScopeSpans().AppendEmpty().Spans().AppendEmpty() - s.SetName("a") - s.SetSpanID(pcommon.NewSpanID([8]byte{0, 0, 0, 0, 0, 0, 0, 1})) - - ctx := metadata.NewIncomingContext(context.Background(), metadata.MD{}) - _, err := runTraceMock(ctx, td, mockConfig{useAPIKeyHeader: true}) - require.Error(t, err) -} - -func TestExportTracePartialData(t *testing.T) { - ptrace := newTestTraces() - ptrace.ResourceSpans().At(0).ScopeSpans().At(0).Spans().At(0).SetTraceID(pcommon.NewTraceID([16]byte{})) - ptrace.ResourceSpans().At(0).ScopeSpans().At(0).Spans().At(1).SetSpanID(pcommon.NewSpanID([8]byte{})) - - _, err := runTraceMock(context.Background(), ptrace, mockConfig{useAPIKeyHeader: false}) - require.Error(t, err) - assert.True(t, strings.Contains(err.Error(), errInvalidSpanID.Error())) - assert.True(t, strings.Contains(err.Error(), errInvalidTraceID.Error())) -} - -func TestExportTraceDataMinimum(t *testing.T) { - td := ptrace.NewTraces() - s1 := td.ResourceSpans().AppendEmpty().ScopeSpans().AppendEmpty().Spans().AppendEmpty() - s1.SetName("root") - s1.SetTraceID(pcommon.NewTraceID([16]byte{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1})) - s1.SetSpanID(pcommon.NewSpanID([8]byte{0, 0, 0, 0, 0, 0, 0, 1})) - - expected := []Batch{ - { - Common: Common{ - Attributes: map[string]string{ - "collector.name": testCollectorName, - "collector.version": testCollectorVersion, - }, - }, - Spans: []Span{ - { - ID: "0000000000000001", - TraceID: "01010101010101010101010101010101", - Attributes: map[string]interface{}{ - "name": "root", - }, - }, - }, - }, - } - - testTraceData(t, expected, td, "") - testTraceData(t, expected, td, "0000000000000000000000000000000000000000") - testTraceData(t, expected, td, "NRII-api-key") -} - -func TestExportTraceDataFullTrace(t *testing.T) { - td := ptrace.NewTraces() - rs := td.ResourceSpans().AppendEmpty() - rs.Resource().Attributes().UpsertString("service.name", "test-service") - rs.Resource().Attributes().UpsertString("resource", "R1") - sps := rs.ScopeSpans().AppendEmpty().Spans() - s1 := sps.AppendEmpty() - s1.SetName("root") - s1.SetTraceID(pcommon.NewTraceID([16]byte{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1})) - s1.SetSpanID(pcommon.NewSpanID([8]byte{0, 0, 0, 0, 0, 0, 0, 1})) - s2 := sps.AppendEmpty() - s2.SetName("client") - s2.SetTraceID(pcommon.NewTraceID([16]byte{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1})) - s2.SetSpanID(pcommon.NewSpanID([8]byte{0, 0, 0, 0, 0, 0, 0, 2})) - s2.SetParentSpanID(pcommon.NewSpanID([8]byte{0, 0, 0, 0, 0, 0, 0, 1})) - s3 := sps.AppendEmpty() - s3.SetName("server") - s3.SetTraceID(pcommon.NewTraceID([16]byte{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1})) - s3.SetSpanID(pcommon.NewSpanID([8]byte{0, 0, 0, 0, 0, 0, 0, 3})) - s3.SetParentSpanID(pcommon.NewSpanID([8]byte{0, 0, 0, 0, 0, 0, 0, 2})) - - expected := []Batch{ - { - Common: Common{ - Attributes: map[string]string{ - "collector.name": testCollectorName, - "collector.version": testCollectorVersion, - "resource": "R1", - "service.name": "test-service", - }, - }, - Spans: []Span{ - { - ID: "0000000000000001", - TraceID: "01010101010101010101010101010101", - Attributes: map[string]interface{}{ - "name": "root", - }, - }, - { - ID: "0000000000000002", - TraceID: "01010101010101010101010101010101", - Attributes: map[string]interface{}{ - "name": "client", - "parent.id": "0000000000000001", - }, - }, - { - ID: "0000000000000003", - TraceID: "01010101010101010101010101010101", - Attributes: map[string]interface{}{ - "name": "server", - "parent.id": "0000000000000002", - }, - }, - }, - }, - } - - testTraceData(t, expected, td, "") - testTraceData(t, expected, td, "0000000000000000000000000000000000000000") - testTraceData(t, expected, td, "NRII-api-key") -} - -func TestExportMetricUnsupported(t *testing.T) { - ms := pmetric.NewMetrics() - m := ms.ResourceMetrics().AppendEmpty().ScopeMetrics().AppendEmpty().Metrics().AppendEmpty() - m.SetDataType(pmetric.MetricDataTypeHistogram) - dp := m.Histogram().DataPoints().AppendEmpty() - dp.SetCount(1) - dp.SetSum(1) - dp.SetTimestamp(pcommon.NewTimestampFromTime(time.Now())) - - _, err := runMetricMock(context.Background(), ms, mockConfig{useAPIKeyHeader: false}) - var unsupportedErr *errUnsupportedMetricType - assert.ErrorAs(t, err, &unsupportedErr, "error was not the expected unsupported metric type error") -} - -func TestExportMetricDataMinimal(t *testing.T) { - desc := "physical property of matter that quantitatively expresses hot and cold" - unit := "K" - md := &agentmetricspb.ExportMetricsServiceRequest{ - Metrics: []*metricspb.Metric{ - { - MetricDescriptor: &metricspb.MetricDescriptor{ - Name: "temperature", - Description: desc, - Unit: unit, - Type: metricspb.MetricDescriptor_GAUGE_DOUBLE, - LabelKeys: []*metricspb.LabelKey{ - {Key: "location"}, - {Key: "elevation"}, - }, - }, - Timeseries: []*metricspb.TimeSeries{ - { - LabelValues: []*metricspb.LabelValue{ - {Value: "Portland", HasValue: true}, - {Value: "0", HasValue: true}, - }, - Points: []*metricspb.Point{ - { - Timestamp: ×tamppb.Timestamp{ - Seconds: 100, - }, - Value: &metricspb.Point_DoubleValue{ - DoubleValue: 293.15, - }, - }, - }, - }, - }, - }, - }, - } - - expected := []Batch{ - { - Common: Common{ - Attributes: map[string]string{ - "collector.name": testCollectorName, - "collector.version": testCollectorVersion, - }, - }, - Metrics: []Metric{ - { - Name: "temperature", - Type: "gauge", - Value: 293.15, - Timestamp: int64(100 * time.Microsecond), - Attributes: map[string]interface{}{ - "description": desc, - "unit": unit, - "location": "Portland", - "elevation": "0", - }, - }, - }, - }, - } - - testMetricData(t, expected, md, "NRII-api-key") - testMetricData(t, expected, md, "0000000000000000000000000000000000000000") - testMetricData(t, expected, md, "") -} - -func TestExportMetricDataFull(t *testing.T) { - desc := "physical property of matter that quantitatively expresses hot and cold" - unit := "K" - md := &agentmetricspb.ExportMetricsServiceRequest{ - Node: &commonpb.Node{ - ServiceInfo: &commonpb.ServiceInfo{Name: "test-service"}, - }, - Resource: &resourcepb.Resource{ - Labels: map[string]string{ - "resource": "R1", - }, - }, - Metrics: []*metricspb.Metric{ - { - MetricDescriptor: &metricspb.MetricDescriptor{ - Name: "temperature", - Description: desc, - Unit: unit, - Type: metricspb.MetricDescriptor_GAUGE_DOUBLE, - LabelKeys: []*metricspb.LabelKey{ - {Key: "location"}, - {Key: "elevation"}, - }, - }, - Timeseries: []*metricspb.TimeSeries{ - { - LabelValues: []*metricspb.LabelValue{ - {Value: "Portland", HasValue: true}, - {Value: "0", HasValue: true}, - }, - Points: []*metricspb.Point{ - { - Timestamp: ×tamppb.Timestamp{ - Seconds: 100, - }, - Value: &metricspb.Point_DoubleValue{ - DoubleValue: 293.15, - }, - }, - { - Timestamp: ×tamppb.Timestamp{ - Seconds: 101, - }, - Value: &metricspb.Point_DoubleValue{ - DoubleValue: 293.15, - }, - }, - { - Timestamp: ×tamppb.Timestamp{ - Seconds: 102, - }, - Value: &metricspb.Point_DoubleValue{ - DoubleValue: 293.45, - }, - }, - }, - }, - { - LabelValues: []*metricspb.LabelValue{ - {Value: "Denver", HasValue: true}, - {Value: "5280", HasValue: true}, - }, - Points: []*metricspb.Point{ - { - Timestamp: ×tamppb.Timestamp{ - Seconds: 99, - }, - Value: &metricspb.Point_DoubleValue{ - DoubleValue: 290.05, - }, - }, - { - Timestamp: ×tamppb.Timestamp{ - Seconds: 106, - }, - Value: &metricspb.Point_DoubleValue{ - DoubleValue: 293.15, - }, - }, - }, - }, - }, - }, - }, - } - - expected := []Batch{ - { - Common: Common{ - Attributes: map[string]string{ - "collector.name": testCollectorName, - "collector.version": testCollectorVersion, - "resource": "R1", - "service.name": "test-service", - }, - }, - Metrics: []Metric{ - { - Name: "temperature", - Type: "gauge", - Value: 293.15, - Timestamp: int64(100 * time.Microsecond), - Attributes: map[string]interface{}{ - "description": desc, - "unit": unit, - "location": "Portland", - "elevation": "0", - }, - }, - { - Name: "temperature", - Type: "gauge", - Value: 293.15, - Timestamp: int64(101 * time.Microsecond), - Attributes: map[string]interface{}{ - "description": desc, - "unit": unit, - "location": "Portland", - "elevation": "0", - }, - }, - { - Name: "temperature", - Type: "gauge", - Value: 293.45, - Timestamp: int64(102 * time.Microsecond), - Attributes: map[string]interface{}{ - "description": desc, - "unit": unit, - "location": "Portland", - "elevation": "0", - }, - }, - { - Name: "temperature", - Type: "gauge", - Value: 290.05, - Timestamp: int64(99 * time.Microsecond), - Attributes: map[string]interface{}{ - "description": desc, - "unit": unit, - "location": "Denver", - "elevation": "5280", - }, - }, - { - Name: "temperature", - Type: "gauge", - Value: 293.15, - Timestamp: int64(106 * time.Microsecond), - Attributes: map[string]interface{}{ - "description": desc, - "unit": unit, - "location": "Denver", - "elevation": "5280", - }, - }, - }, - }, - } - - testMetricData(t, expected, md, "") - testMetricData(t, expected, md, "0000000000000000000000000000000000000000") - testMetricData(t, expected, md, "NRII-api-key") -} - -func TestExportLogs(t *testing.T) { - timestamp := time.Now() - logs := plog.NewLogs() - rlog := logs.ResourceLogs().AppendEmpty() - rlog.Resource().Attributes().InsertString("resource", "R1") - rlog.Resource().Attributes().InsertString("service.name", "test-service") - l := rlog.ScopeLogs().AppendEmpty().LogRecords().AppendEmpty() - l.SetTimestamp(pcommon.NewTimestampFromTime(timestamp)) - l.Body().SetStringVal("log body") - l.Attributes().InsertString("foo", "bar") - - expected := []Batch{ - { - Common: Common{ - Attributes: map[string]string{ - "collector.name": testCollectorName, - "collector.version": testCollectorVersion, - "resource": "R1", - "service.name": "test-service", - }, - }, - Logs: []Log{ - { - Message: "log body", - Timestamp: timestamp.UnixNano() / (1000 * 1000), - Attributes: map[string]interface{}{ - "foo": "bar", - }, - }, - }, - }, - } - - testLogData(t, expected, logs, "") - testLogData(t, expected, logs, "0000000000000000000000000000000000000000") - testLogData(t, expected, logs, "NRII-api-key") -} - -func TestCreatesClientOptionWithVersionInUserAgent(t *testing.T) { - expectedUserAgentSubstring := "NewRelic-OpenTelemetry-Collector/latest otelcol" - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - - m := &Mock{ - Batches: make([]Batch, 0, 1), - StatusCode: 202, - } - - cfg := mockConfig{useAPIKeyHeader: false} - - srv := m.Server() - defer srv.Close() - - f := NewFactory() - c := f.CreateDefaultConfig().(*Config) - urlString := srv.URL - if cfg.serverURL != "" { - urlString = cfg.serverURL - } - u, _ := url.Parse(urlString) - - if cfg.useAPIKeyHeader { - c.TracesConfig.APIKeyHeader = "api-key" - } else { - c.TracesConfig.APIKey = "NRII-1" - } - c.TracesConfig.insecure, c.TracesConfig.HostOverride = true, u.Host - exp, err := f.CreateTracesExporter(context.Background(), componenttest.NewNopExporterCreateSettings(), c) - require.NoError(t, err) - - ptrace := ptrace.NewTraces() - s := ptrace.ResourceSpans().AppendEmpty().ScopeSpans().AppendEmpty().Spans().AppendEmpty() - s.SetName("root") - s.SetTraceID(pcommon.NewTraceID([16]byte{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1})) - s.SetSpanID(pcommon.NewSpanID([8]byte{0, 0, 0, 0, 0, 0, 0, 1})) - - err = exp.ConsumeTraces(ctx, ptrace) - require.NoError(t, err) - err = exp.Shutdown(ctx) - require.NoError(t, err) - - assert.Contains(t, m.Header[http.CanonicalHeaderKey("user-agent")][0], expectedUserAgentSubstring) -} - -func TestBadSpanResourceGeneratesError(t *testing.T) { - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - - m := &Mock{ - Batches: make([]Batch, 0, 1), - StatusCode: 202, - } - - cfg := mockConfig{useAPIKeyHeader: false} - - srv := m.Server() - defer srv.Close() - - f := NewFactory() - c := f.CreateDefaultConfig().(*Config) - urlString := srv.URL - if cfg.serverURL != "" { - urlString = cfg.serverURL - } - u, _ := url.Parse(urlString) - - if cfg.useAPIKeyHeader { - c.TracesConfig.APIKeyHeader = "api-key" - } else { - c.TracesConfig.APIKey = "NRII-1" - } - c.TracesConfig.insecure, c.TracesConfig.HostOverride = true, u.Host - exp, err := f.CreateTracesExporter(context.Background(), componenttest.NewNopExporterCreateSettings(), c) - require.NoError(t, err) - - ptrace := ptrace.NewTraces() - rs := ptrace.ResourceSpans().AppendEmpty() - rs.Resource().Attributes().InsertDouble("badattribute", math.Inf(1)) - s := rs.ScopeSpans().AppendEmpty().Spans().AppendEmpty() - s.SetName("root") - s.SetTraceID(pcommon.NewTraceID([16]byte{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1})) - s.SetSpanID(pcommon.NewSpanID([8]byte{0, 0, 0, 0, 0, 0, 0, 1})) - - errorFromConsumeTraces := exp.ConsumeTraces(ctx, ptrace) - - err = exp.Shutdown(ctx) - require.NoError(t, err) - - require.Error(t, errorFromConsumeTraces) -} - -func TestBadMetricResourceGeneratesError(t *testing.T) { - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - - m := &Mock{ - Batches: make([]Batch, 0, 1), - StatusCode: 202, - } - - cfg := mockConfig{useAPIKeyHeader: false} - - srv := m.Server() - defer srv.Close() - - f := NewFactory() - c := f.CreateDefaultConfig().(*Config) - urlString := srv.URL - if cfg.serverURL != "" { - urlString = cfg.serverURL - } - u, _ := url.Parse(urlString) - - if cfg.useAPIKeyHeader { - c.MetricsConfig.APIKeyHeader = "api-key" - } else { - c.MetricsConfig.APIKey = "NRII-1" - } - c.TracesConfig.insecure, c.TracesConfig.HostOverride = true, u.Host - exp, err := f.CreateMetricsExporter(context.Background(), componenttest.NewNopExporterCreateSettings(), c) - require.NoError(t, err) - - md := pmetric.NewMetrics() - rm := md.ResourceMetrics().AppendEmpty() - rm.Resource().Attributes().InsertDouble("badattribute", math.Inf(1)) - metric := rm.ScopeMetrics().AppendEmpty().Metrics().AppendEmpty() - metric.SetName("testmetric") - - errorFromConsumeMetrics := exp.ConsumeMetrics(ctx, md) - - err = exp.Shutdown(ctx) - require.NoError(t, err) - - require.Error(t, errorFromConsumeMetrics) -} - -func TestBadLogResourceGeneratesError(t *testing.T) { - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - - m := &Mock{ - Batches: make([]Batch, 0, 1), - StatusCode: 202, - } - - cfg := mockConfig{useAPIKeyHeader: false} - - srv := m.Server() - defer srv.Close() - - f := NewFactory() - c := f.CreateDefaultConfig().(*Config) - urlString := srv.URL - if cfg.serverURL != "" { - urlString = cfg.serverURL - } - u, _ := url.Parse(urlString) - - if cfg.useAPIKeyHeader { - c.LogsConfig.APIKeyHeader = "api-key" - } else { - c.LogsConfig.APIKey = "NRII-1" - } - c.TracesConfig.insecure, c.TracesConfig.HostOverride = true, u.Host - exp, err := f.CreateLogsExporter(context.Background(), componenttest.NewNopExporterCreateSettings(), c) - require.NoError(t, err) - - ld := plog.NewLogs() - rl := ld.ResourceLogs().AppendEmpty() - rl.Resource().Attributes().InsertDouble("badattribute", math.Inf(1)) - rl.ScopeLogs().AppendEmpty().LogRecords().AppendEmpty() - - errorFromConsumeLogs := exp.ConsumeLogs(ctx, ld) - - err = exp.Shutdown(ctx) - require.NoError(t, err) - - require.Error(t, errorFromConsumeLogs) -} - -func TestFailureToRecordMetricsDoesNotAffectExportingData(t *testing.T) { - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - if err := view.Register(MetricViews()...); err != nil { - t.Fail() - } - defer view.Unregister(MetricViews()...) - - m := &Mock{ - Batches: make([]Batch, 0, 1), - StatusCode: 202, - } - - cfg := mockConfig{useAPIKeyHeader: false} - - srv := m.Server() - defer srv.Close() - - f := NewFactory() - c := f.CreateDefaultConfig().(*Config) - urlString := srv.URL - if cfg.serverURL != "" { - urlString = cfg.serverURL - } - u, _ := url.Parse(urlString) - - if cfg.useAPIKeyHeader { - c.TracesConfig.APIKeyHeader = "api-key" - } else { - c.TracesConfig.APIKey = "NRII-1" - } - c.TracesConfig.insecure, c.TracesConfig.HostOverride = true, u.Host - - exp, err := f.CreateTracesExporter(context.Background(), componenttest.NewNopExporterCreateSettings(), c) - require.NoError(t, err) - - ptrace := ptrace.NewTraces() - s := ptrace.ResourceSpans().AppendEmpty().ScopeSpans().AppendEmpty().Spans().AppendEmpty() - s.SetName("root") - s.SetTraceID(pcommon.NewTraceID([16]byte{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1})) - s.SetSpanID(pcommon.NewSpanID([8]byte{0, 0, 0, 0, 0, 0, 0, 1})) - - // Create a long string so that the user-agent will be too long and cause RecordMetric to fail - b := make([]byte, 300) - for i := 0; i < 300; i++ { - b[i] = 'a' - } - consumeCtx := metadata.NewIncomingContext(context.Background(), metadata.MD{"user-agent": []string{string(b)}}) - err = exp.ConsumeTraces(consumeCtx, ptrace) - require.NoError(t, err) - err = exp.Shutdown(ctx) - require.NoError(t, err) - - assert.Contains(t, m.Header[http.CanonicalHeaderKey("user-agent")][0], testCollectorName) -} - -func newTestTraces() ptrace.Traces { - td := ptrace.NewTraces() - sps := td.ResourceSpans().AppendEmpty().ScopeSpans().AppendEmpty().Spans() - s1 := sps.AppendEmpty() - s1.SetName("a") - s1.SetTraceID(pcommon.NewTraceID([16]byte{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1})) - s1.SetSpanID(pcommon.NewSpanID([8]byte{0, 0, 0, 0, 0, 0, 0, 1})) - s2 := sps.AppendEmpty() - s2.SetName("b") - s2.SetTraceID(pcommon.NewTraceID([16]byte{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1})) - s2.SetSpanID(pcommon.NewSpanID([8]byte{0, 0, 0, 0, 0, 0, 0, 2})) - return td -} diff --git a/exporter/newrelicexporter/testdata/config.yaml b/exporter/newrelicexporter/testdata/config.yaml deleted file mode 100644 index eefae30c0e3c..000000000000 --- a/exporter/newrelicexporter/testdata/config.yaml +++ /dev/null @@ -1,37 +0,0 @@ -receivers: - nop: - -processors: - nop: - -exporters: - newrelic: - newrelic/alt: - apikey: a1b2c3d4 - timeout: 30s - retry: - enabled: false - initial_interval: 0 - max_interval: 0 - max_elapsed_time: 0 - metrics: - host_override: alt.metrics.newrelic.com - traces: - host_override: alt.spans.newrelic.com - logs: - host_override: alt.logs.newrelic.com - -service: - pipelines: - traces: - receivers: [nop] - processors: [nop] - exporters: [newrelic] - metrics: - receivers: [nop] - processors: [nop] - exporters: [newrelic] - logs: - receivers: [nop] - processors: [nop] - exporters: [newrelic] diff --git a/exporter/newrelicexporter/transformer.go b/exporter/newrelicexporter/transformer.go deleted file mode 100644 index 72220410559e..000000000000 --- a/exporter/newrelicexporter/transformer.go +++ /dev/null @@ -1,436 +0,0 @@ -// 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 newrelicexporter // import "github.com/open-telemetry/opentelemetry-collector-contrib/exporter/newrelicexporter" - -import ( - "errors" - "fmt" - "math" - "strings" - "time" - - "github.com/newrelic/newrelic-telemetry-sdk-go/telemetry" - "go.opentelemetry.io/collector/component" - "go.opentelemetry.io/collector/consumer/consumererror" - "go.opentelemetry.io/collector/pdata/pcommon" - "go.opentelemetry.io/collector/pdata/plog" - "go.opentelemetry.io/collector/pdata/pmetric" - "go.opentelemetry.io/collector/pdata/ptrace" - conventions "go.opentelemetry.io/collector/semconv/v1.6.1" - "go.uber.org/zap" -) - -const ( - unitAttrKey = "unit" - descriptionAttrKey = "description" - collectorNameKey = "collector.name" - collectorVersionKey = "collector.version" - droppedAttributesCountKey = "otel.dropped_attributes_count" - droppedEventsCountKey = "otel.dropped_events_count" - statusCodeKey = "otel.status_code" - statusDescriptionKey = "otel.status_description" - spanKindKey = "span.kind" - spanIDKey = "span.id" - traceIDKey = "trace.id" - logSeverityTextKey = "log.level" - logSeverityNumKey = "log.levelNum" -) - -type transformer struct { - logger *zap.Logger - OverrideAttributes map[string]interface{} - details *exportMetadata -} - -func newTransformer(logger *zap.Logger, buildInfo *component.BuildInfo, details *exportMetadata) *transformer { - overrideAttributes := make(map[string]interface{}) - if buildInfo != nil { - overrideAttributes[collectorNameKey] = buildInfo.Command - if buildInfo.Version != "" { - overrideAttributes[collectorVersionKey] = buildInfo.Version - } - } - - return &transformer{logger: logger, OverrideAttributes: overrideAttributes, details: details} -} - -func (t *transformer) CommonAttributes(resource pcommon.Resource, lib pcommon.InstrumentationScope) map[string]interface{} { - resourceAttrs := resource.Attributes() - commonAttrs := resourceAttrs.AsRaw() - t.TrackAttributes(attributeLocationResource, resourceAttrs) - - if n := lib.Name(); n != "" { - commonAttrs[conventions.OtelLibraryName] = n - if v := lib.Version(); v != "" { - commonAttrs[conventions.OtelLibraryVersion] = v - } - } - - for k, v := range t.OverrideAttributes { - commonAttrs[k] = v - } - - return commonAttrs -} - -var ( - errInvalidSpanID = errors.New("SpanID is invalid") - errInvalidTraceID = errors.New("TraceID is invalid") -) - -func (t *transformer) Span(span ptrace.Span) (telemetry.Span, error) { - startTime := span.StartTimestamp().AsTime() - sp := telemetry.Span{ - // HexString validates the IDs, it will be an empty string if invalid. - ID: span.SpanID().HexString(), - TraceID: span.TraceID().HexString(), - ParentID: span.ParentSpanID().HexString(), - Name: span.Name(), - Timestamp: startTime, - Duration: span.EndTimestamp().AsTime().Sub(startTime), - Attributes: t.SpanAttributes(span), - Events: t.SpanEvents(span), - } - - spanMetadataKey := spanStatsKey{ - hasEvents: sp.Events != nil, - hasLinks: span.Links().Len() > 0, - } - t.details.spanMetadataCount[spanMetadataKey]++ - - if sp.ID == "" { - return sp, errInvalidSpanID - } - if sp.TraceID == "" { - return sp, errInvalidTraceID - } - - return sp, nil -} - -func (t *transformer) Log(log plog.LogRecord) (telemetry.Log, error) { - var message string - - if bodyString := log.Body().StringVal(); bodyString != "" { - message = bodyString - } - - logAttrs := log.Attributes() - attrs := make(map[string]interface{}, logAttrs.Len()+5) - - for k, v := range logAttrs.AsRaw() { - // Only include attribute if not an override attribute - if _, isOverrideKey := t.OverrideAttributes[k]; !isOverrideKey { - attrs[k] = v - } - } - t.TrackAttributes(attributeLocationLog, logAttrs) - - if !log.TraceID().IsEmpty() { - attrs[traceIDKey] = log.TraceID().HexString() - } - - if !log.SpanID().IsEmpty() { - attrs[spanIDKey] = log.SpanID().HexString() - } - - if log.SeverityText() != "" { - attrs[logSeverityTextKey] = log.SeverityText() - } - - if log.SeverityNumber() != 0 { - attrs[logSeverityNumKey] = int32(log.SeverityNumber()) - } - - if droppedAttributesCount := log.DroppedAttributesCount(); droppedAttributesCount > 0 { - attrs[droppedAttributesCountKey] = droppedAttributesCount - } - - return telemetry.Log{ - Message: message, - Timestamp: log.Timestamp().AsTime(), - Attributes: attrs, - }, nil -} - -func (t *transformer) SpanAttributes(span ptrace.Span) map[string]interface{} { - spanAttrs := span.Attributes() - length := spanAttrs.Len() - - var hasStatusCode, hasStatusDesc bool - s := span.Status() - if s.Code() != ptrace.StatusCodeUnset { - hasStatusCode = true - length++ - if s.Message() != "" { - hasStatusDesc = true - length++ - } - } - - validSpanKind := span.Kind() != ptrace.SpanKindUnspecified - if validSpanKind { - length++ - } - - attrs := make(map[string]interface{}, length) - - if hasStatusCode { - code := strings.TrimPrefix(span.Status().Code().String(), "STATUS_CODE_") - attrs[statusCodeKey] = code - } - if hasStatusDesc { - attrs[statusDescriptionKey] = span.Status().Message() - } - - // Add span kind if it is set - if validSpanKind { - kind := strings.TrimPrefix(span.Kind().String(), "SPAN_KIND_") - attrs[spanKindKey] = strings.ToLower(kind) - } - - if droppedAttributesCount := span.DroppedAttributesCount(); droppedAttributesCount > 0 { - attrs[droppedAttributesCountKey] = droppedAttributesCount - } - - if droppedEventsCount := span.DroppedEventsCount(); droppedEventsCount > 0 { - attrs[droppedEventsCountKey] = droppedEventsCount - } - - for k, v := range spanAttrs.AsRaw() { - // Only include attribute if not an override attribute - if _, isOverrideKey := t.OverrideAttributes[k]; !isOverrideKey { - attrs[k] = v - } - } - t.TrackAttributes(attributeLocationSpan, spanAttrs) - - return attrs -} - -// SpanEvents transforms the recorded events of span into New Relic tracing events. -func (t *transformer) SpanEvents(span ptrace.Span) []telemetry.Event { - length := span.Events().Len() - if length == 0 { - return nil - } - - events := make([]telemetry.Event, length) - - for i := 0; i < length; i++ { - event := span.Events().At(i) - eventAttrs := event.Attributes() - events[i] = telemetry.Event{ - EventType: event.Name(), - Timestamp: event.Timestamp().AsTime(), - Attributes: eventAttrs.AsRaw(), - } - - if droppedAttributesCount := event.DroppedAttributesCount(); droppedAttributesCount > 0 { - events[i].Attributes[droppedAttributesCountKey] = droppedAttributesCount - } - - t.TrackAttributes(attributeLocationSpanEvent, eventAttrs) - } - return events -} - -type errUnsupportedMetricType struct { - metricType string - metricName string - numDataPoints int -} - -func (e errUnsupportedMetricType) Error() string { - return fmt.Sprintf("unsupported metric %v (%v)", e.metricName, e.metricType) -} - -func (t *transformer) Metric(m pmetric.Metric) ([]telemetry.Metric, error) { - var output []telemetry.Metric - baseAttributes := t.BaseMetricAttributes(m) - - dataType := m.DataType() - k := metricStatsKey{MetricType: dataType} - - switch dataType { - case pmetric.MetricDataTypeGauge: - t.details.metricMetadataCount[k]++ - // "StartTimestampUnixNano" is ignored for all data points. - gauge := m.Gauge() - points := gauge.DataPoints() - output = make([]telemetry.Metric, 0, points.Len()) - for l := 0; l < points.Len(); l++ { - point := points.At(l) - - var val float64 - switch point.ValueType() { - case pmetric.NumberDataPointValueTypeDouble: - val = point.DoubleVal() - case pmetric.NumberDataPointValueTypeInt: - val = float64(point.IntVal()) - } - attributes := t.MetricAttributes(baseAttributes, point.Attributes()) - - nrMetric := telemetry.Gauge{ - Name: m.Name(), - Attributes: attributes, - Value: val, - Timestamp: point.Timestamp().AsTime(), - } - output = append(output, nrMetric) - } - case pmetric.MetricDataTypeSum: - sum := m.Sum() - temporality := sum.AggregationTemporality() - k.MetricTemporality = temporality - t.details.metricMetadataCount[k]++ - - points := sum.DataPoints() - output = make([]telemetry.Metric, 0, points.Len()) - for l := 0; l < points.Len(); l++ { - point := points.At(l) - attributes := t.MetricAttributes(baseAttributes, point.Attributes()) - var val float64 - switch point.ValueType() { - case pmetric.NumberDataPointValueTypeDouble: - val = point.DoubleVal() - case pmetric.NumberDataPointValueTypeInt: - val = float64(point.IntVal()) - } - - if temporality != pmetric.MetricAggregationTemporalityDelta { - t.logger.Debug("Converting metric to gauge where AggregationTemporality != Delta", - zap.String("MetricName", m.Name()), - zap.Stringer("Temporality", temporality), - zap.Stringer("MetricType", dataType), - ) - nrMetric := telemetry.Gauge{ - Name: m.Name(), - Attributes: attributes, - Value: val, - Timestamp: point.Timestamp().AsTime(), - } - output = append(output, nrMetric) - } else { - nrMetric := telemetry.Count{ - Name: m.Name(), - Attributes: attributes, - Value: val, - Timestamp: point.StartTimestamp().AsTime(), - Interval: time.Duration(point.Timestamp() - point.StartTimestamp()), - ForceIntervalValid: true, - } - output = append(output, nrMetric) - } - } - case pmetric.MetricDataTypeHistogram: - hist := m.Histogram() - k.MetricTemporality = hist.AggregationTemporality() - t.details.metricMetadataCount[k]++ - return nil, consumererror.NewPermanent(&errUnsupportedMetricType{metricType: k.MetricType.String(), metricName: m.Name(), numDataPoints: hist.DataPoints().Len()}) - case pmetric.MetricDataTypeSummary: - t.details.metricMetadataCount[k]++ - summary := m.Summary() - points := summary.DataPoints() - output = make([]telemetry.Metric, 0, points.Len()) - name := m.Name() - for l := 0; l < points.Len(); l++ { - point := points.At(l) - quantiles := point.QuantileValues() - minQuantile := math.NaN() - maxQuantile := math.NaN() - - if quantiles.Len() > 0 { - quantileA := quantiles.At(0) - if quantileA.Quantile() == 0 { - minQuantile = quantileA.Value() - } - if quantiles.Len() > 1 { - quantileB := quantiles.At(quantiles.Len() - 1) - if quantileB.Quantile() == 1 { - maxQuantile = quantileB.Value() - } - } else if quantileA.Quantile() == 1 { - maxQuantile = quantileA.Value() - } - } - - attributes := t.MetricAttributes(baseAttributes, point.Attributes()) - nrMetric := telemetry.Summary{ - Name: name, - Attributes: attributes, - Count: float64(point.Count()), - Sum: point.Sum(), - Min: minQuantile, - Max: maxQuantile, - Timestamp: point.StartTimestamp().AsTime(), - Interval: time.Duration(point.Timestamp() - point.StartTimestamp()), - ForceIntervalValid: true, - } - - output = append(output, nrMetric) - } - default: - t.details.metricMetadataCount[k]++ - } - return output, nil -} - -func (t *transformer) BaseMetricAttributes(metric pmetric.Metric) map[string]interface{} { - length := 0 - - if metric.Unit() != "" { - length++ - } - - if metric.Description() != "" { - length++ - } - - attrs := make(map[string]interface{}, length) - - if metric.Unit() != "" { - attrs[unitAttrKey] = metric.Unit() - } - - if metric.Description() != "" { - attrs[descriptionAttrKey] = metric.Description() - } - return attrs -} - -func (t *transformer) MetricAttributes(baseAttributes map[string]interface{}, attrMap pcommon.Map) map[string]interface{} { - rawMap := make(map[string]interface{}, len(baseAttributes)+attrMap.Len()) - for k, v := range baseAttributes { - rawMap[k] = v - } - attrMap.Range(func(k string, v pcommon.Value) bool { - // Only include attribute if not an override attribute - if _, isOverrideKey := t.OverrideAttributes[k]; !isOverrideKey { - rawMap[k] = v.AsString() - } - return true - }) - - return rawMap -} - -func (t *transformer) TrackAttributes(location attributeLocation, attributeMap pcommon.Map) { - attributeMap.Range(func(_ string, v pcommon.Value) bool { - statsKey := attributeStatsKey{location: location, attributeType: v.Type()} - t.details.attributeMetadataCount[statsKey]++ - return true - }) -} diff --git a/exporter/newrelicexporter/transformer_test.go b/exporter/newrelicexporter/transformer_test.go deleted file mode 100644 index 857771a8a4d8..000000000000 --- a/exporter/newrelicexporter/transformer_test.go +++ /dev/null @@ -1,942 +0,0 @@ -// 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 newrelicexporter - -import ( - "context" - "errors" - "math" - "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" - "go.opentelemetry.io/collector/consumer/consumererror" - "go.opentelemetry.io/collector/pdata/pcommon" - "go.opentelemetry.io/collector/pdata/plog" - "go.opentelemetry.io/collector/pdata/pmetric" - "go.opentelemetry.io/collector/pdata/ptrace" - conventions "go.opentelemetry.io/collector/semconv/v1.6.1" - "go.uber.org/zap" -) - -func TestCommonAttributes(t *testing.T) { - buildInfo := &component.BuildInfo{ - Command: "the-collector", - Version: "0.0.1", - } - - resource := pcommon.NewResource() - resource.Attributes().InsertString("resource", "R1") - - ilm := pcommon.NewInstrumentationScope() - ilm.SetName("test name") - ilm.SetVersion("test version") - - details := newTraceMetadata(context.TODO()) - commonAttrs := newTransformer(zap.NewNop(), buildInfo, &details).CommonAttributes(resource, ilm) - assert.Equal(t, "the-collector", commonAttrs[collectorNameKey]) - assert.Equal(t, "0.0.1", commonAttrs[collectorVersionKey]) - assert.Equal(t, "R1", commonAttrs["resource"]) - assert.Equal(t, "test name", commonAttrs[conventions.OtelLibraryName]) - assert.Equal(t, "test version", commonAttrs[conventions.OtelLibraryVersion]) - - assert.Equal(t, 1, len(details.attributeMetadataCount)) - assert.Equal(t, 1, details.attributeMetadataCount[attributeStatsKey{location: attributeLocationResource, attributeType: pcommon.ValueTypeString}]) -} - -func TestDoesNotCaptureResourceAttributeMetadata(t *testing.T) { - buildInfo := &component.BuildInfo{ - Command: "the-collector", - Version: "0.0.1", - } - - resource := pcommon.NewResource() - - ilm := pcommon.NewInstrumentationScope() - ilm.SetName("test name") - ilm.SetVersion("test version") - - details := newTraceMetadata(context.TODO()) - commonAttrs := newTransformer(zap.NewNop(), buildInfo, &details).CommonAttributes(resource, ilm) - - assert.Greater(t, len(commonAttrs), 0) - assert.Equal(t, 0, len(details.attributeMetadataCount)) -} - -func TestCaptureSpanMetadata(t *testing.T) { - details := newTraceMetadata(context.TODO()) - transform := newTransformer(zap.NewNop(), nil, &details) - - tests := []struct { - name string - err error - spanFunc func() ptrace.Span - wantKey spanStatsKey - }{ - { - name: "no events or links", - spanFunc: func() ptrace.Span { - s := ptrace.NewSpan() - s.SetSpanID(pcommon.NewSpanID([...]byte{0, 0, 0, 0, 0, 0, 0, 1})) - s.SetName("no events or links") - return s - }, - err: errInvalidTraceID, - wantKey: spanStatsKey{hasEvents: false, hasLinks: false}, - }, - { - name: "has events but no links", - spanFunc: func() ptrace.Span { - s := ptrace.NewSpan() - s.SetTraceID(pcommon.NewTraceID([...]byte{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1})) - s.SetName("invalid SpanID") - s.Events().AppendEmpty() - return s - }, - err: errInvalidSpanID, - wantKey: spanStatsKey{hasEvents: true, hasLinks: false}, - }, - { - name: "no events but has links", - spanFunc: func() ptrace.Span { - s := ptrace.NewSpan() - s.SetTraceID(pcommon.NewTraceID([...]byte{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1})) - s.SetSpanID(pcommon.NewSpanID([...]byte{0, 0, 0, 0, 0, 0, 0, 1})) - s.SetName("no events but has links") - s.Links().AppendEmpty() - return s - }, - wantKey: spanStatsKey{hasEvents: false, hasLinks: true}, - }, - { - name: "has events and links", - spanFunc: func() ptrace.Span { - s := ptrace.NewSpan() - s.SetTraceID(pcommon.NewTraceID([...]byte{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1})) - s.SetSpanID(pcommon.NewSpanID([...]byte{0, 0, 0, 0, 0, 0, 0, 2})) - s.SetParentSpanID(pcommon.NewSpanID([...]byte{0, 0, 0, 0, 0, 0, 0, 1})) - s.SetName("has events and links") - s.Events().AppendEmpty() - s.Links().AppendEmpty() - return s - }, - wantKey: spanStatsKey{hasEvents: true, hasLinks: true}, - }, - } - - for _, test := range tests { - t.Run(test.name, func(t *testing.T) { - _, err := transform.Span(test.spanFunc()) - if test.err != nil { - assert.True(t, errors.Is(err, test.err)) - } else { - require.NoError(t, err) - } - assert.Equal(t, 1, details.spanMetadataCount[test.wantKey]) - }) - } -} - -func TestCaptureSpanAttributeMetadata(t *testing.T) { - details := newTraceMetadata(context.TODO()) - transform := newTransformer(zap.NewNop(), nil, &details) - - s := ptrace.NewSpan() - s.SetTraceID(pcommon.NewTraceID([...]byte{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1})) - s.SetSpanID(pcommon.NewSpanID([...]byte{0, 0, 0, 0, 0, 0, 0, 2})) - s.SetParentSpanID(pcommon.NewSpanID([...]byte{0, 0, 0, 0, 0, 0, 0, 1})) - s.SetName("test span") - - se := s.Events().AppendEmpty() - se.Attributes().InsertBool("testattr", true) - - s.Attributes().InsertInt("spanattr", 42) - - _, err := transform.Span(s) - - require.NoError(t, err) - assert.Equal(t, 2, len(details.attributeMetadataCount)) - assert.Equal(t, 1, details.attributeMetadataCount[attributeStatsKey{location: attributeLocationSpan, attributeType: pcommon.ValueTypeInt}]) - assert.Equal(t, 1, details.attributeMetadataCount[attributeStatsKey{location: attributeLocationSpanEvent, attributeType: pcommon.ValueTypeBool}]) -} - -func TestDoesNotCaptureSpanAttributeMetadata(t *testing.T) { - details := newTraceMetadata(context.TODO()) - transform := newTransformer(zap.NewNop(), nil, &details) - - s := ptrace.NewSpan() - s.SetTraceID(pcommon.NewTraceID([...]byte{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1})) - s.SetSpanID(pcommon.NewSpanID([...]byte{0, 0, 0, 0, 0, 0, 0, 2})) - s.SetParentSpanID(pcommon.NewSpanID([...]byte{0, 0, 0, 0, 0, 0, 0, 1})) - s.SetName("test span") - s.Events().AppendEmpty() - - _, err := transform.Span(s) - - require.NoError(t, err) - assert.Equal(t, 0, len(details.attributeMetadataCount)) -} - -func TestTransformSpan(t *testing.T) { - now := time.Unix(100, 0) - details := newTraceMetadata(context.TODO()) - transform := newTransformer(zap.NewNop(), nil, &details) - - tests := []struct { - name string - err error - spanFunc func() ptrace.Span - want telemetry.Span - }{ - { - name: "invalid TraceID", - spanFunc: func() ptrace.Span { - s := ptrace.NewSpan() - s.SetSpanID(pcommon.NewSpanID([...]byte{0, 0, 0, 0, 0, 0, 0, 1})) - s.SetName("invalid TraceID") - return s - }, - err: errInvalidTraceID, - want: telemetry.Span{ - ID: "0000000000000001", - Name: "invalid TraceID", - Timestamp: time.Unix(0, 0).UTC(), - Attributes: map[string]interface{}{}, - }, - }, - { - name: "invalid SpanID", - spanFunc: func() ptrace.Span { - s := ptrace.NewSpan() - s.SetTraceID(pcommon.NewTraceID([...]byte{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1})) - s.SetName("invalid SpanID") - return s - }, - err: errInvalidSpanID, - want: telemetry.Span{ - TraceID: "01010101010101010101010101010101", - Name: "invalid SpanID", - Timestamp: time.Unix(0, 0).UTC(), - Attributes: map[string]interface{}{}, - }, - }, - { - name: "root", - spanFunc: func() ptrace.Span { - s := ptrace.NewSpan() - s.SetTraceID(pcommon.NewTraceID([...]byte{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1})) - s.SetSpanID(pcommon.NewSpanID([...]byte{0, 0, 0, 0, 0, 0, 0, 1})) - s.SetName("root") - return s - }, - want: telemetry.Span{ - ID: "0000000000000001", - TraceID: "01010101010101010101010101010101", - Name: "root", - Timestamp: time.Unix(0, 0).UTC(), - Attributes: map[string]interface{}{}, - Events: nil, - }, - }, - { - name: "client", - spanFunc: func() ptrace.Span { - s := ptrace.NewSpan() - s.SetTraceID(pcommon.NewTraceID([...]byte{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1})) - s.SetSpanID(pcommon.NewSpanID([...]byte{0, 0, 0, 0, 0, 0, 0, 2})) - s.SetParentSpanID(pcommon.NewSpanID([...]byte{0, 0, 0, 0, 0, 0, 0, 1})) - s.SetName("client") - return s - }, - want: telemetry.Span{ - ID: "0000000000000002", - TraceID: "01010101010101010101010101010101", - Name: "client", - ParentID: "0000000000000001", - Timestamp: time.Unix(0, 0).UTC(), - Attributes: map[string]interface{}{}, - Events: nil, - }, - }, - { - name: "error code", - spanFunc: func() ptrace.Span { - s := ptrace.NewSpan() - s.SetName("error code") - s.SetTraceID(pcommon.NewTraceID([16]byte{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1})) - s.SetSpanID(pcommon.NewSpanID([8]byte{0, 0, 0, 0, 0, 0, 0, 3})) - s.Status().SetCode(ptrace.StatusCodeError) - return s - }, - want: telemetry.Span{ - ID: "0000000000000003", - TraceID: "01010101010101010101010101010101", - Name: "error code", - Timestamp: time.Unix(0, 0).UTC(), - Attributes: map[string]interface{}{ - statusCodeKey: "ERROR", - }, - Events: nil, - }, - }, - { - name: "error message", - spanFunc: func() ptrace.Span { - s := ptrace.NewSpan() - s.SetName("error message") - s.SetTraceID(pcommon.NewTraceID([16]byte{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1})) - s.SetSpanID(pcommon.NewSpanID([8]byte{0, 0, 0, 0, 0, 0, 0, 3})) - s.Status().SetCode(ptrace.StatusCodeError) - s.Status().SetMessage("error message") - return s - }, - want: telemetry.Span{ - ID: "0000000000000003", - TraceID: "01010101010101010101010101010101", - Name: "error message", - Timestamp: time.Unix(0, 0).UTC(), - Attributes: map[string]interface{}{ - statusCodeKey: "ERROR", - statusDescriptionKey: "error message", - }, - Events: nil, - }, - }, - { - name: "attributes", - spanFunc: func() ptrace.Span { - s := ptrace.NewSpan() - s.SetName("attrs") - s.SetTraceID(pcommon.NewTraceID([16]byte{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1})) - s.SetSpanID(pcommon.NewSpanID([8]byte{0, 0, 0, 0, 0, 0, 0, 4})) - s.Attributes().UpsertBool("prod", true) - s.Attributes().UpsertInt("weight", 10) - s.Attributes().UpsertDouble("score", 99.8) - s.Attributes().UpsertString("user", "alice") - return s - }, - want: telemetry.Span{ - ID: "0000000000000004", - TraceID: "01010101010101010101010101010101", - Name: "attrs", - Timestamp: time.Unix(0, 0).UTC(), - Attributes: map[string]interface{}{ - "prod": true, - "weight": int64(10), - "score": 99.8, - "user": "alice", - }, - Events: nil, - }, - }, - { - name: "with timestamps", - spanFunc: func() ptrace.Span { - s := ptrace.NewSpan() - s.SetTraceID(pcommon.NewTraceID([...]byte{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1})) - s.SetSpanID(pcommon.NewSpanID([...]byte{0, 0, 0, 0, 0, 0, 0, 5})) - s.SetName("with time") - s.SetStartTimestamp(pcommon.NewTimestampFromTime(now)) - s.SetEndTimestamp(pcommon.NewTimestampFromTime(now.Add(time.Second * 5))) - return s - }, - want: telemetry.Span{ - ID: "0000000000000005", - TraceID: "01010101010101010101010101010101", - Name: "with time", - Timestamp: now.UTC(), - Duration: time.Second * 5, - Attributes: map[string]interface{}{}, - Events: nil, - }, - }, - { - name: "span kind server", - spanFunc: func() ptrace.Span { - s := ptrace.NewSpan() - s.SetTraceID(pcommon.NewTraceID([...]byte{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1})) - s.SetSpanID(pcommon.NewSpanID([...]byte{0, 0, 0, 0, 0, 0, 0, 6})) - s.SetName("span kind server") - s.SetKind(ptrace.SpanKindServer) - return s - }, - want: telemetry.Span{ - ID: "0000000000000006", - TraceID: "01010101010101010101010101010101", - Name: "span kind server", - Timestamp: time.Unix(0, 0).UTC(), - Attributes: map[string]interface{}{ - spanKindKey: "server", - }, - Events: nil, - }, - }, - { - name: "with events", - spanFunc: func() ptrace.Span { - s := ptrace.NewSpan() - s.SetTraceID(pcommon.NewTraceID([...]byte{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1})) - s.SetSpanID(pcommon.NewSpanID([...]byte{0, 0, 0, 0, 0, 0, 0, 7})) - s.SetName("with events") - - event := s.Events().AppendEmpty() - event.SetName("this is the event name") - event.SetTimestamp(pcommon.NewTimestampFromTime(now)) - return s - }, - want: telemetry.Span{ - ID: "0000000000000007", - TraceID: "01010101010101010101010101010101", - Name: "with events", - Timestamp: time.Unix(0, 0).UTC(), - Attributes: map[string]interface{}{}, - Events: []telemetry.Event{ - { - EventType: "this is the event name", - Timestamp: now.UTC(), - Attributes: map[string]interface{}{}, - }, - }, - }, - }, - { - name: "with dropped attributes", - spanFunc: func() ptrace.Span { - s := ptrace.NewSpan() - s.SetTraceID(pcommon.NewTraceID([...]byte{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1})) - s.SetSpanID(pcommon.NewSpanID([...]byte{0, 0, 0, 0, 0, 0, 0, 8})) - s.SetName("with dropped attributes") - s.SetDroppedAttributesCount(2) - return s - }, - want: telemetry.Span{ - ID: "0000000000000008", - TraceID: "01010101010101010101010101010101", - Name: "with dropped attributes", - Timestamp: time.Unix(0, 0).UTC(), - Attributes: map[string]interface{}{ - droppedAttributesCountKey: uint32(2), - }, - Events: nil, - }, - }, - { - name: "with dropped events", - spanFunc: func() ptrace.Span { - s := ptrace.NewSpan() - s.SetTraceID(pcommon.NewTraceID([...]byte{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1})) - s.SetSpanID(pcommon.NewSpanID([...]byte{0, 0, 0, 0, 0, 0, 0, 9})) - s.SetName("with dropped events") - s.SetDroppedEventsCount(3) - return s - }, - want: telemetry.Span{ - ID: "0000000000000009", - TraceID: "01010101010101010101010101010101", - Name: "with dropped events", - Timestamp: time.Unix(0, 0).UTC(), - Attributes: map[string]interface{}{ - droppedEventsCountKey: uint32(3), - }, - Events: nil, - }, - }, - { - name: "with dropped attributes on events", - spanFunc: func() ptrace.Span { - s := ptrace.NewSpan() - s.SetTraceID(pcommon.NewTraceID([...]byte{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1})) - s.SetSpanID(pcommon.NewSpanID([...]byte{0, 0, 0, 0, 0, 0, 0, 10})) - s.SetName("with dropped attributes on events") - - ev := ptrace.NewSpanEventSlice() - ev.EnsureCapacity(1) - event := ev.AppendEmpty() - event.SetName("this is the event name") - event.SetTimestamp(pcommon.NewTimestampFromTime(now)) - event.SetDroppedAttributesCount(1) - tgt := s.Events().AppendEmpty() - event.CopyTo(tgt) - return s - }, - want: telemetry.Span{ - ID: "000000000000000a", - TraceID: "01010101010101010101010101010101", - Name: "with dropped attributes on events", - Timestamp: time.Unix(0, 0).UTC(), - Attributes: map[string]interface{}{}, - Events: []telemetry.Event{ - { - EventType: "this is the event name", - Timestamp: now.UTC(), - Attributes: map[string]interface{}{ - droppedAttributesCountKey: uint32(1), - }, - }, - }, - }, - }, - } - - for _, test := range tests { - t.Run(test.name, func(t *testing.T) { - got, err := transform.Span(test.spanFunc()) - if test.err != nil { - assert.True(t, errors.Is(err, test.err)) - } else { - require.NoError(t, err) - } - assert.Equal(t, test.want, got) - }) - } -} - -func testTransformMetric(t *testing.T, metric pmetric.Metric, want []telemetry.Metric) { - comparer := func(t *testing.T, want []telemetry.Metric, got []telemetry.Metric) { - assert.Equal(t, want, got) - } - testTransformMetricWithComparer(t, metric, want, comparer) -} - -func testTransformMetricWithComparer(t *testing.T, metric pmetric.Metric, want []telemetry.Metric, compare func(t *testing.T, want []telemetry.Metric, got []telemetry.Metric)) { - details := newMetricMetadata(context.Background()) - transform := newTransformer(zap.NewNop(), &component.BuildInfo{ - Command: testCollectorName, - Version: testCollectorVersion, - }, &details) - got, err := transform.Metric(metric) - require.NoError(t, err) - compare(t, want, got) - - assert.Equal(t, len(details.metricMetadataCount), 1) - for k, v := range details.metricMetadataCount { - assert.Equal(t, metric.DataType(), k.MetricType) - assert.Equal(t, 1, v) - } -} - -func testTransformMetricWithError(t *testing.T, metric pmetric.Metric, expectedErrorType interface{}) { - details := newMetricMetadata(context.Background()) - transform := newTransformer(zap.NewNop(), &component.BuildInfo{ - Command: testCollectorName, - Version: testCollectorVersion, - }, &details) - _, err := transform.Metric(metric) - assert.IsType(t, expectedErrorType, err) - - assert.Equal(t, len(details.metricMetadataCount), 1) - for k, v := range details.metricMetadataCount { - assert.Equal(t, metric.DataType(), k.MetricType) - assert.Equal(t, 1, v) - } -} - -func TestTransformGauge(t *testing.T) { - ts := pcommon.NewTimestampFromTime(time.Unix(1, 0)) - expected := []telemetry.Metric{ - telemetry.Gauge{ - Name: "gauge", - Value: 42.0, - Timestamp: ts.AsTime(), - Attributes: map[string]interface{}{ - "unit": "1", - "description": "description", - }, - }, - } - { - m := pmetric.NewMetric() - m.SetName("gauge") - m.SetDescription("description") - m.SetUnit("1") - m.SetDataType(pmetric.MetricDataTypeGauge) - gd := m.Gauge() - dp := gd.DataPoints().AppendEmpty() - dp.SetTimestamp(ts) - dp.SetDoubleVal(42.0) - t.Run("Double", func(t *testing.T) { testTransformMetric(t, m, expected) }) - } - { - m := pmetric.NewMetric() - m.SetName("gauge") - m.SetDescription("description") - m.SetUnit("1") - m.SetDataType(pmetric.MetricDataTypeGauge) - gi := m.Gauge() - dp := gi.DataPoints().AppendEmpty() - dp.SetTimestamp(ts) - dp.SetIntVal(42) - t.Run("Int64", func(t *testing.T) { testTransformMetric(t, m, expected) }) - } -} - -func TestTransformSum(t *testing.T) { - start := pcommon.NewTimestampFromTime(time.Unix(1, 0)) - end := pcommon.NewTimestampFromTime(time.Unix(3, 0)) - - expected := []telemetry.Metric{ - telemetry.Count{ - Name: "sum", - Value: 42.0, - Timestamp: start.AsTime(), - Interval: time.Second * 2, - Attributes: map[string]interface{}{ - "unit": "1", - "description": "description", - }, - ForceIntervalValid: true, - }, - } - expectedGauge := []telemetry.Metric{ - telemetry.Gauge{ - Name: "sum", - Value: 42.0, - Timestamp: end.AsTime(), - Attributes: map[string]interface{}{ - "unit": "1", - "description": "description", - }, - }, - } - - { - m := pmetric.NewMetric() - m.SetName("sum") - m.SetDescription("description") - m.SetUnit("1") - m.SetDataType(pmetric.MetricDataTypeSum) - d := m.Sum() - d.SetAggregationTemporality(pmetric.MetricAggregationTemporalityDelta) - dp := d.DataPoints().AppendEmpty() - dp.SetStartTimestamp(start) - dp.SetTimestamp(end) - dp.SetDoubleVal(42.0) - t.Run("Sum-Delta", func(t *testing.T) { testTransformMetric(t, m, expected) }) - } - { - m := pmetric.NewMetric() - m.SetName("sum") - m.SetDescription("description") - m.SetUnit("1") - m.SetDataType(pmetric.MetricDataTypeSum) - d := m.Sum() - d.SetAggregationTemporality(pmetric.MetricAggregationTemporalityCumulative) - dp := d.DataPoints().AppendEmpty() - dp.SetStartTimestamp(start) - dp.SetTimestamp(end) - dp.SetDoubleVal(42.0) - t.Run("Sum-Cumulative", func(t *testing.T) { testTransformMetric(t, m, expectedGauge) }) - } - { - m := pmetric.NewMetric() - m.SetName("sum") - m.SetDescription("description") - m.SetUnit("1") - m.SetDataType(pmetric.MetricDataTypeSum) - d := m.Sum() - d.SetAggregationTemporality(pmetric.MetricAggregationTemporalityDelta) - dp := d.DataPoints().AppendEmpty() - dp.SetStartTimestamp(start) - dp.SetTimestamp(end) - dp.SetIntVal(42.0) - t.Run("IntSum-Delta", func(t *testing.T) { testTransformMetric(t, m, expected) }) - } - { - m := pmetric.NewMetric() - m.SetName("sum") - m.SetDescription("description") - m.SetUnit("1") - m.SetDataType(pmetric.MetricDataTypeSum) - d := m.Sum() - d.SetAggregationTemporality(pmetric.MetricAggregationTemporalityCumulative) - dp := d.DataPoints().AppendEmpty() - dp.SetStartTimestamp(start) - dp.SetTimestamp(end) - dp.SetIntVal(42.0) - t.Run("IntSum-Cumulative", func(t *testing.T) { testTransformMetric(t, m, expectedGauge) }) - } -} - -func TestTransformDeltaSummary(t *testing.T) { - testTransformDeltaSummaryWithValues(t, "Double With Min and Max", 2, 7, 1, 6) - testTransformDeltaSummaryWithValues(t, "Double With Min and No Max", 1, 1, 1, math.NaN()) - testTransformDeltaSummaryWithValues(t, "Double With Max and No Min", 1, 1, math.NaN(), 1) - testTransformDeltaSummaryWithValues(t, "Double With No Min and No Max", 0, 0, math.NaN(), math.NaN()) -} - -func testTransformDeltaSummaryWithValues(t *testing.T, testName string, count uint64, sum float64, min float64, max float64) { - start := pcommon.NewTimestampFromTime(time.Unix(1, 0)) - end := pcommon.NewTimestampFromTime(time.Unix(3, 0)) - - expected := []telemetry.Metric{ - telemetry.Summary{ - Name: "summary", - Count: float64(count), - Sum: sum, - Min: min, - Max: max, - Timestamp: time.Unix(1, 0).UTC(), - Interval: 2 * time.Second, - Attributes: map[string]interface{}{ - "description": "description", - "unit": "s", - "foo": "bar", - }, - }, - } - - comparer := func(t *testing.T, want []telemetry.Metric, got []telemetry.Metric) { - assert.Equal(t, len(want), len(got)) - - for i := 0; i < len(want); i++ { - wantedSummary, ok := want[i].(telemetry.Summary) - assert.True(t, ok) - gotSummary, ok := got[i].(telemetry.Summary) - assert.True(t, ok) - assert.Equal(t, wantedSummary.Name, gotSummary.Name) - assert.Equal(t, wantedSummary.Count, gotSummary.Count) - assert.Equal(t, wantedSummary.Sum, gotSummary.Sum) - assert.Equal(t, wantedSummary.Timestamp, gotSummary.Timestamp) - assert.Equal(t, wantedSummary.Interval, gotSummary.Interval) - assert.Equal(t, wantedSummary.Attributes, gotSummary.Attributes) - if math.IsNaN(wantedSummary.Min) { - assert.True(t, math.IsNaN(gotSummary.Min)) - } else { - assert.Equal(t, wantedSummary.Min, gotSummary.Min) - } - if math.IsNaN(wantedSummary.Max) { - assert.True(t, math.IsNaN(gotSummary.Max)) - } else { - assert.Equal(t, wantedSummary.Max, gotSummary.Max) - } - } - } - - m := pmetric.NewMetric() - m.SetName("summary") - m.SetDescription("description") - m.SetUnit("s") - m.SetDataType(pmetric.MetricDataTypeSummary) - ds := m.Summary() - dp := ds.DataPoints().AppendEmpty() - dp.SetStartTimestamp(start) - dp.SetTimestamp(end) - dp.SetSum(sum) - dp.SetCount(count) - dp.Attributes().InsertString("foo", "bar") - q := dp.QuantileValues() - if !math.IsNaN(min) { - minQuantile := q.AppendEmpty() - minQuantile.SetQuantile(0) - minQuantile.SetValue(min) - } - if !math.IsNaN(max) { - maxQuantile := q.AppendEmpty() - maxQuantile.SetQuantile(1) - maxQuantile.SetValue(max) - } - - t.Run(testName, func(t *testing.T) { testTransformMetricWithComparer(t, m, expected, comparer) }) -} - -func TestUnsupportedMetricTypes(t *testing.T) { - start := pcommon.NewTimestampFromTime(time.Unix(1, 0)) - end := pcommon.NewTimestampFromTime(time.Unix(3, 0)) - { - m := pmetric.NewMetric() - m.SetName("no") - m.SetDescription("no") - m.SetUnit("1") - m.SetDataType(pmetric.MetricDataTypeHistogram) - h := m.Histogram() - dp := h.DataPoints().AppendEmpty() - dp.SetStartTimestamp(start) - dp.SetTimestamp(end) - dp.SetCount(2) - dp.SetSum(8.0) - dp.SetExplicitBounds([]float64{3, 7, 11}) - dp.SetBucketCounts([]uint64{1, 1, 0, 0}) - h.SetAggregationTemporality(pmetric.MetricAggregationTemporalityDelta) - - t.Run("DoubleHistogram", func(t *testing.T) { - testTransformMetricWithError(t, m, consumererror.NewPermanent(&errUnsupportedMetricType{})) - }) - } -} - -func TestTransformUnknownMetricType(t *testing.T) { - metric := pmetric.NewMetric() - details := newMetricMetadata(context.Background()) - transform := newTransformer(zap.NewNop(), &component.BuildInfo{ - Command: testCollectorName, - Version: testCollectorVersion, - }, &details) - - got, err := transform.Metric(metric) - - require.NoError(t, err) - assert.Nil(t, got) - assert.Equal(t, 1, details.metricMetadataCount[metricStatsKey{MetricType: pmetric.MetricDataTypeNone}]) -} - -func TestTransformer_Log(t *testing.T) { - tests := []struct { - name string - logFunc func() plog.LogRecord - want telemetry.Log - }{ - { - name: "Basic Conversion", - logFunc: func() plog.LogRecord { - log := plog.NewLogRecord() - timestamp := pcommon.NewTimestampFromTime(time.Unix(0, 0).UTC()) - log.SetTimestamp(timestamp) - return log - }, - want: telemetry.Log{ - Message: "", - Timestamp: time.Unix(0, 0).UTC(), - Attributes: map[string]interface{}{}, - }, - }, - { - name: "With Log attributes", - logFunc: func() plog.LogRecord { - log := plog.NewLogRecord() - log.Attributes().InsertString("foo", "bar") - log.Body().SetStringVal("Hello World") - return log - }, - want: telemetry.Log{ - Message: "Hello World", - Timestamp: time.Unix(0, 0).UTC(), - Attributes: map[string]interface{}{"foo": "bar"}, - }, - }, - { - name: "With severity number", - logFunc: func() plog.LogRecord { - log := plog.NewLogRecord() - log.SetSeverityNumber(plog.SeverityNumberWARN) - log.Body().SetStringVal("bloopbleep") - return log - }, - want: telemetry.Log{ - Message: "bloopbleep", - Timestamp: time.Unix(0, 0).UTC(), - Attributes: map[string]interface{}{"log.levelNum": int32(13)}, - }, - }, - { - name: "With severity text", - logFunc: func() plog.LogRecord { - log := plog.NewLogRecord() - log.SetSeverityText("SEVERE") - log.Body().SetStringVal("bloopbleep") - return log - }, - want: telemetry.Log{ - Message: "bloopbleep", - Timestamp: time.Unix(0, 0).UTC(), - Attributes: map[string]interface{}{"log.level": "SEVERE"}, - }, - }, - { - name: "With traceID and spanID", - logFunc: func() plog.LogRecord { - log := plog.NewLogRecord() - timestamp := pcommon.NewTimestampFromTime(time.Unix(0, 0).UTC()) - log.SetTraceID(pcommon.NewTraceID([...]byte{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1})) - log.SetSpanID(pcommon.NewSpanID([...]byte{0, 0, 0, 0, 0, 0, 0, 1})) - log.SetTimestamp(timestamp) - return log - }, - want: telemetry.Log{ - Message: "", - Timestamp: time.Unix(0, 0).UTC(), - Attributes: map[string]interface{}{ - "trace.id": "01010101010101010101010101010101", - "span.id": "0000000000000001", - }, - }, - }, - { - name: "With dropped attribute count", - logFunc: func() plog.LogRecord { - log := plog.NewLogRecord() - timestamp := pcommon.NewTimestampFromTime(time.Unix(0, 0).UTC()) - log.SetTimestamp(timestamp) - log.SetDroppedAttributesCount(4) - return log - }, - want: telemetry.Log{ - Message: "", - Timestamp: time.Unix(0, 0).UTC(), - Attributes: map[string]interface{}{ - droppedAttributesCountKey: uint32(4), - }, - }, - }, - } - for _, test := range tests { - t.Run(test.name, func(t *testing.T) { - details := newLogMetadata(context.TODO()) - transform := newTransformer(zap.NewNop(), nil, &details) - got, _ := transform.Log(test.logFunc()) - assert.EqualValues(t, test.want, got) - }) - } -} - -func TestCaptureLogAttributeMetadata(t *testing.T) { - log := plog.NewLogRecord() - log.Attributes().InsertString("foo", "bar") - log.Body().SetStringVal("Hello World") - - details := newLogMetadata(context.TODO()) - transform := newTransformer(zap.NewNop(), nil, &details) - _, err := transform.Log(log) - - require.NoError(t, err) - assert.Equal(t, 1, len(details.attributeMetadataCount)) - assert.Equal(t, 1, details.attributeMetadataCount[attributeStatsKey{location: attributeLocationLog, attributeType: pcommon.ValueTypeString}]) -} - -func TestDoesNotCaptureLogAttributeMetadata(t *testing.T) { - log := plog.NewLogRecord() - log.Body().SetStringVal("Hello World") - - details := newLogMetadata(context.TODO()) - transform := newTransformer(zap.NewNop(), nil, &details) - _, err := transform.Log(log) - - require.NoError(t, err) - assert.Equal(t, 0, len(details.attributeMetadataCount)) -} - -func TestUnsupportedMetricErrorCreation(t *testing.T) { - e := errUnsupportedMetricType{ - metricType: "testType", - metricName: "testName", - numDataPoints: 1, - } - - errorMessage := e.Error() - - assert.Equal(t, "unsupported metric testName (testType)", errorMessage) -} diff --git a/go.mod b/go.mod index f308636b1331..c3b7275d5e41 100644 --- a/go.mod +++ b/go.mod @@ -29,7 +29,6 @@ require ( github.com/open-telemetry/opentelemetry-collector-contrib/exporter/loadbalancingexporter v0.50.0 github.com/open-telemetry/opentelemetry-collector-contrib/exporter/logzioexporter v0.50.0 github.com/open-telemetry/opentelemetry-collector-contrib/exporter/lokiexporter v0.50.0 - github.com/open-telemetry/opentelemetry-collector-contrib/exporter/newrelicexporter v0.50.0 github.com/open-telemetry/opentelemetry-collector-contrib/exporter/opencensusexporter v0.50.0 github.com/open-telemetry/opentelemetry-collector-contrib/exporter/parquetexporter v0.50.0 github.com/open-telemetry/opentelemetry-collector-contrib/exporter/prometheusexporter v0.50.0 @@ -338,7 +337,6 @@ require ( github.com/mostynb/go-grpc-compression v1.1.16 // indirect github.com/mrunalp/fileutils v0.5.0 // indirect github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f // indirect - github.com/newrelic/newrelic-telemetry-sdk-go v0.8.1 // indirect github.com/observiq/ctimefmt v1.0.0 // indirect github.com/olivere/elastic v6.2.37+incompatible // indirect github.com/open-telemetry/opentelemetry-collector-contrib/extension/observer v0.50.0 // indirect @@ -584,8 +582,6 @@ replace github.com/open-telemetry/opentelemetry-collector-contrib/exporter/logzi replace github.com/open-telemetry/opentelemetry-collector-contrib/exporter/lokiexporter => ./exporter/lokiexporter -replace github.com/open-telemetry/opentelemetry-collector-contrib/exporter/newrelicexporter => ./exporter/newrelicexporter - replace github.com/open-telemetry/opentelemetry-collector-contrib/exporter/opencensusexporter => ./exporter/opencensusexporter replace github.com/open-telemetry/opentelemetry-collector-contrib/exporter/parquetexporter => ./exporter/parquetexporter diff --git a/go.sum b/go.sum index 4d33e76b708e..0bc2ccc57867 100644 --- a/go.sum +++ b/go.sum @@ -1826,8 +1826,6 @@ github.com/nats-io/nkeys v0.3.0/go.mod h1:gvUNGjVcM2IPr5rCsRsC6Wb3Hr2CQAm08dsxtV github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c= github.com/nbutton23/zxcvbn-go v0.0.0-20180912185939-ae427f1e4c1d/go.mod h1:o96djdrsSGy3AWPyBgZMAGfxZNfgntdJG+11KU4QvbU= github.com/ncw/swift v1.0.47/go.mod h1:23YIA4yWVnGwv2dQlN4bB7egfYX6YLn0Yo/S6zZO/ZM= -github.com/newrelic/newrelic-telemetry-sdk-go v0.8.1 h1:6OX5VXMuj2salqNBc41eXKz6K+nV6OB/hhlGnAKCbwU= -github.com/newrelic/newrelic-telemetry-sdk-go v0.8.1/go.mod h1:2kY6OeOxrJ+RIQlVjWDc/pZlT3MIf30prs6drzMfJ6E= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= github.com/npillmayer/nestext v0.1.3/go.mod h1:h2lrijH8jpicr25dFY+oAJLyzlya6jhnuG+zWp9L0Uk= github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= diff --git a/internal/components/components.go b/internal/components/components.go index 64e73eb20ba3..ca6355e12159 100644 --- a/internal/components/components.go +++ b/internal/components/components.go @@ -51,7 +51,6 @@ import ( "github.com/open-telemetry/opentelemetry-collector-contrib/exporter/loadbalancingexporter" "github.com/open-telemetry/opentelemetry-collector-contrib/exporter/logzioexporter" "github.com/open-telemetry/opentelemetry-collector-contrib/exporter/lokiexporter" - "github.com/open-telemetry/opentelemetry-collector-contrib/exporter/newrelicexporter" "github.com/open-telemetry/opentelemetry-collector-contrib/exporter/opencensusexporter" "github.com/open-telemetry/opentelemetry-collector-contrib/exporter/parquetexporter" "github.com/open-telemetry/opentelemetry-collector-contrib/exporter/prometheusexporter" @@ -262,7 +261,6 @@ func Components() (component.Factories, error) { loggingexporter.NewFactory(), logzioexporter.NewFactory(), lokiexporter.NewFactory(), - newrelicexporter.NewFactory(), opencensusexporter.NewFactory(), otlpexporter.NewFactory(), otlphttpexporter.NewFactory(), diff --git a/internal/components/exporters_test.go b/internal/components/exporters_test.go index 234845152cc9..1b2798d86dea 100644 --- a/internal/components/exporters_test.go +++ b/internal/components/exporters_test.go @@ -55,7 +55,6 @@ import ( "github.com/open-telemetry/opentelemetry-collector-contrib/exporter/loadbalancingexporter" "github.com/open-telemetry/opentelemetry-collector-contrib/exporter/logzioexporter" "github.com/open-telemetry/opentelemetry-collector-contrib/exporter/lokiexporter" - "github.com/open-telemetry/opentelemetry-collector-contrib/exporter/newrelicexporter" "github.com/open-telemetry/opentelemetry-collector-contrib/exporter/opencensusexporter" "github.com/open-telemetry/opentelemetry-collector-contrib/exporter/parquetexporter" "github.com/open-telemetry/opentelemetry-collector-contrib/exporter/prometheusexporter" @@ -389,14 +388,6 @@ func TestDefaultExporters(t *testing.T) { return cfg }, }, - { - exporter: "newrelic", - getConfigFn: func() config.Exporter { - cfg := expFactories["newrelic"].CreateDefaultConfig().(*newrelicexporter.Config) - cfg.CommonConfig.HostOverride = "http://" + endpoint - return cfg - }, - }, { exporter: "sentry", getConfigFn: func() config.Exporter { diff --git a/versions.yaml b/versions.yaml index 0aeb1c0796d1..72ed65a8520f 100644 --- a/versions.yaml +++ b/versions.yaml @@ -48,7 +48,6 @@ module-sets: - github.com/open-telemetry/opentelemetry-collector-contrib/exporter/loadbalancingexporter - github.com/open-telemetry/opentelemetry-collector-contrib/exporter/logzioexporter - github.com/open-telemetry/opentelemetry-collector-contrib/exporter/lokiexporter - - github.com/open-telemetry/opentelemetry-collector-contrib/exporter/newrelicexporter - github.com/open-telemetry/opentelemetry-collector-contrib/exporter/observiqexporter - github.com/open-telemetry/opentelemetry-collector-contrib/exporter/opencensusexporter - github.com/open-telemetry/opentelemetry-collector-contrib/exporter/parquetexporter From fc932302941eda8508d4d8b70961d92be979288c Mon Sep 17 00:00:00 2001 From: jack-berg Date: Tue, 10 May 2022 12:12:44 -0500 Subject: [PATCH 2/2] gofmt, gotidy, add link to changelog --- CHANGELOG.md | 2 +- cmd/configschema/go.sum | 2 -- go.sum | 2 -- 3 files changed, 1 insertion(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8b8ce2d0f08a..6b68607f53ae 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,7 +7,7 @@ - `datadogexporter`: Replace HistogramMode defined as string with enum. - `pkg/translator/signalfx`: Change signalfx translator to expose To/From translator structs. (#9740) - `transformprocessor`: Add parameter validation to `truncate_all` and `limit` functions. The `limit` parameter can no longer be negative. (#9783) -- `newrelicexporter` deleted. Use New Relic native OTLP ingest instead. +- `newrelicexporter` deleted. Use New Relic [native OTLP ingest](https://docs.newrelic.com/docs/more-integrations/open-source-telemetry-integrations/opentelemetry/opentelemetry-setup/) instead. (#9894) ### 🚩 Deprecations 🚩 diff --git a/cmd/configschema/go.sum b/cmd/configschema/go.sum index e3e95e546a89..006c008cbf29 100644 --- a/cmd/configschema/go.sum +++ b/cmd/configschema/go.sum @@ -1620,8 +1620,6 @@ github.com/nats-io/nkeys v0.3.0/go.mod h1:gvUNGjVcM2IPr5rCsRsC6Wb3Hr2CQAm08dsxtV github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c= github.com/nbutton23/zxcvbn-go v0.0.0-20180912185939-ae427f1e4c1d/go.mod h1:o96djdrsSGy3AWPyBgZMAGfxZNfgntdJG+11KU4QvbU= github.com/ncw/swift v1.0.47/go.mod h1:23YIA4yWVnGwv2dQlN4bB7egfYX6YLn0Yo/S6zZO/ZM= -github.com/newrelic/newrelic-telemetry-sdk-go v0.8.1 h1:6OX5VXMuj2salqNBc41eXKz6K+nV6OB/hhlGnAKCbwU= -github.com/newrelic/newrelic-telemetry-sdk-go v0.8.1/go.mod h1:2kY6OeOxrJ+RIQlVjWDc/pZlT3MIf30prs6drzMfJ6E= github.com/nginxinc/nginx-plus-go-client v0.6.0/go.mod h1:DBAmdDP71tOhgFPdCMVusegzdKmLVpVL0nVcMX17pbY= github.com/nginxinc/nginx-prometheus-exporter v0.8.1-0.20201110005315-f5a5f8086c19 h1:jR4KbeVA+KYmPq+amRe6AdB4mIfEaSOZGY2zCpqt/p8= github.com/nginxinc/nginx-prometheus-exporter v0.8.1-0.20201110005315-f5a5f8086c19/go.mod h1:L58Se1nwn3cEyHWlcfdlXgiGbHe/efvDbkbi+psz3lA= diff --git a/go.sum b/go.sum index b973eaa57b46..357f34d8b6fd 100644 --- a/go.sum +++ b/go.sum @@ -1619,8 +1619,6 @@ github.com/nats-io/nkeys v0.3.0/go.mod h1:gvUNGjVcM2IPr5rCsRsC6Wb3Hr2CQAm08dsxtV github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c= github.com/nbutton23/zxcvbn-go v0.0.0-20180912185939-ae427f1e4c1d/go.mod h1:o96djdrsSGy3AWPyBgZMAGfxZNfgntdJG+11KU4QvbU= github.com/ncw/swift v1.0.47/go.mod h1:23YIA4yWVnGwv2dQlN4bB7egfYX6YLn0Yo/S6zZO/ZM= -github.com/newrelic/newrelic-telemetry-sdk-go v0.8.1 h1:6OX5VXMuj2salqNBc41eXKz6K+nV6OB/hhlGnAKCbwU= -github.com/newrelic/newrelic-telemetry-sdk-go v0.8.1/go.mod h1:2kY6OeOxrJ+RIQlVjWDc/pZlT3MIf30prs6drzMfJ6E= github.com/nginxinc/nginx-plus-go-client v0.6.0/go.mod h1:DBAmdDP71tOhgFPdCMVusegzdKmLVpVL0nVcMX17pbY= github.com/nginxinc/nginx-prometheus-exporter v0.8.1-0.20201110005315-f5a5f8086c19 h1:jR4KbeVA+KYmPq+amRe6AdB4mIfEaSOZGY2zCpqt/p8= github.com/nginxinc/nginx-prometheus-exporter v0.8.1-0.20201110005315-f5a5f8086c19/go.mod h1:L58Se1nwn3cEyHWlcfdlXgiGbHe/efvDbkbi+psz3lA=