From 6eb654634ea58aabb6aa7ab199de97fbb636a4ff Mon Sep 17 00:00:00 2001 From: Khyati Gandhi <59329594+khyatigandhi6@users.noreply.github.com> Date: Thu, 22 Sep 2022 12:02:51 +0530 Subject: [PATCH 1/9] Logicmonitorexporter implementation fixes --- .chloggen/logicmonitor_implementation.yaml | 16 + cmd/configschema/go.mod | 5 + cmd/configschema/go.sum | 2 + exporter/logicmonitorexporter/Makefile | 1 + exporter/logicmonitorexporter/README.md | 41 ++ .../logicmonitorexporter/authenticator.go | 150 +++++ .../authenticator_test.go | 85 +++ exporter/logicmonitorexporter/config.go | 69 +++ exporter/logicmonitorexporter/config_test.go | 82 +++ exporter/logicmonitorexporter/constants.go | 24 + exporter/logicmonitorexporter/factory.go | 87 +++ exporter/logicmonitorexporter/factory_test.go | 94 +++ exporter/logicmonitorexporter/go.mod | 51 ++ exporter/logicmonitorexporter/go.sum | 475 +++++++++++++++ .../logicmonitorexporter/logs_exporter.go | 134 +++++ .../logs_exporter_test.go | 186 ++++++ exporter/logicmonitorexporter/session.go | 185 ++++++ exporter/logicmonitorexporter/session_test.go | 470 +++++++++++++++ .../testdata/config_logs.yaml | 16 + .../testdata/config_traces.yaml | 22 + .../logicmonitorexporter/traces_exporter.go | 169 ++++++ .../traces_exporter_test.go | 567 ++++++++++++++++++ go.mod | 4 + go.sum | 2 + internal/components/components.go | 2 + internal/components/exporters_test.go | 8 + versions.yaml | 1 + 27 files changed, 2948 insertions(+) create mode 100644 .chloggen/logicmonitor_implementation.yaml create mode 100644 exporter/logicmonitorexporter/Makefile create mode 100644 exporter/logicmonitorexporter/README.md create mode 100644 exporter/logicmonitorexporter/authenticator.go create mode 100644 exporter/logicmonitorexporter/authenticator_test.go create mode 100644 exporter/logicmonitorexporter/config.go create mode 100644 exporter/logicmonitorexporter/config_test.go create mode 100644 exporter/logicmonitorexporter/constants.go create mode 100644 exporter/logicmonitorexporter/factory.go create mode 100644 exporter/logicmonitorexporter/factory_test.go create mode 100644 exporter/logicmonitorexporter/go.mod create mode 100644 exporter/logicmonitorexporter/go.sum create mode 100644 exporter/logicmonitorexporter/logs_exporter.go create mode 100644 exporter/logicmonitorexporter/logs_exporter_test.go create mode 100644 exporter/logicmonitorexporter/session.go create mode 100644 exporter/logicmonitorexporter/session_test.go create mode 100644 exporter/logicmonitorexporter/testdata/config_logs.yaml create mode 100644 exporter/logicmonitorexporter/testdata/config_traces.yaml create mode 100644 exporter/logicmonitorexporter/traces_exporter.go create mode 100644 exporter/logicmonitorexporter/traces_exporter_test.go diff --git a/.chloggen/logicmonitor_implementation.yaml b/.chloggen/logicmonitor_implementation.yaml new file mode 100644 index 000000000000..45f32730a69e --- /dev/null +++ b/.chloggen/logicmonitor_implementation.yaml @@ -0,0 +1,16 @@ +# One of 'breaking', 'deprecation', 'new_component', 'enhancement', 'bug_fix' +change_type: new_component + +# The name of the component, or a single word describing the area of concern, (e.g. filelogreceiver) +component: logicmonitorexporter + +# A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`). +note: New exporter for exporting traces and logs to Logicmonitor Platform + +# One or more tracking issues related to the change +issues: [13727] + +# (Optional) One or more lines of additional information to render under the primary note. +# These lines will be padded with 2 spaces and then inserted directly into the document. +# Use pipe (|) for multiline entries. +subtext: diff --git a/cmd/configschema/go.mod b/cmd/configschema/go.mod index d51c667dd7fc..d560fb010629 100644 --- a/cmd/configschema/go.mod +++ b/cmd/configschema/go.mod @@ -14,6 +14,8 @@ require ( golang.org/x/text v0.4.0 ) +require github.com/logicmonitor/lm-data-sdk-go v0.5.0 // indirect + require ( bitbucket.org/atlassian/go-asap/v2 v2.6.0 // indirect cloud.google.com/go v0.105.0 // indirect @@ -337,6 +339,7 @@ require ( github.com/open-telemetry/opentelemetry-collector-contrib/exporter/jaegerthrifthttpexporter v0.64.0 // indirect github.com/open-telemetry/opentelemetry-collector-contrib/exporter/kafkaexporter v0.64.0 // indirect github.com/open-telemetry/opentelemetry-collector-contrib/exporter/loadbalancingexporter v0.64.0 // indirect + github.com/open-telemetry/opentelemetry-collector-contrib/exporter/logicmonitorexporter v0.64.0 // indirect github.com/open-telemetry/opentelemetry-collector-contrib/exporter/logzioexporter v0.64.0 // indirect github.com/open-telemetry/opentelemetry-collector-contrib/exporter/lokiexporter v0.64.0 // indirect github.com/open-telemetry/opentelemetry-collector-contrib/exporter/mezmoexporter v0.64.0 // indirect @@ -738,6 +741,8 @@ replace github.com/open-telemetry/opentelemetry-collector-contrib/exporter/kafka replace github.com/open-telemetry/opentelemetry-collector-contrib/exporter/loadbalancingexporter => ../../exporter/loadbalancingexporter +replace github.com/open-telemetry/opentelemetry-collector-contrib/exporter/logicmonitorexporter => ../../exporter/logicmonitorexporter + replace github.com/open-telemetry/opentelemetry-collector-contrib/exporter/logzioexporter => ../../exporter/logzioexporter replace github.com/open-telemetry/opentelemetry-collector-contrib/exporter/lokiexporter => ../../exporter/lokiexporter diff --git a/cmd/configschema/go.sum b/cmd/configschema/go.sum index 5d2c92074bab..ad244d4ad25b 100644 --- a/cmd/configschema/go.sum +++ b/cmd/configschema/go.sum @@ -1612,6 +1612,8 @@ github.com/linkedin/goavro/v2 v2.9.8 h1:jN50elxBsGBDGVDEKqUlDuU1cFwJ11K/yrJCBMe/ github.com/linkedin/goavro/v2 v2.9.8/go.mod h1:UgQUb2N/pmueQYH9bfqFioWxzYCZXSfF8Jw03O5sjqA= github.com/linode/linodego v1.8.0 h1:7B2UaWu6C48tZZZrtINWRElAcwzk4TLnL9USjKf3xm0= github.com/linode/linodego v1.8.0/go.mod h1:heqhl91D8QTPVm2k9qZHP78zzbOdTFLXE9NJc3bcc50= +github.com/logicmonitor/lm-data-sdk-go v0.5.0 h1:TFmXsvCOZmp0jOaJys13UKk8BTdcZ06GIuxhIV0O43g= +github.com/logicmonitor/lm-data-sdk-go v0.5.0/go.mod h1:dzWezgvavPjocqpt5KX94/0K4Fsmop8wMinRB293S48= github.com/logrusorgru/aurora v0.0.0-20181002194514-a7b3b318ed4e/go.mod h1:7rIyQOR62GCctdiQpZ/zOJlFyk6y+94wXzv6RNZgaR4= github.com/lucasb-eyer/go-colorful v1.0.2/go.mod h1:0MS4r+7BZKSJ5mw4/S5MPN+qHFF1fYclkSPilDOKW0s= github.com/lucasb-eyer/go-colorful v1.0.3/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0= diff --git a/exporter/logicmonitorexporter/Makefile b/exporter/logicmonitorexporter/Makefile new file mode 100644 index 000000000000..c1496226e590 --- /dev/null +++ b/exporter/logicmonitorexporter/Makefile @@ -0,0 +1 @@ +include ../../Makefile.Common \ No newline at end of file diff --git a/exporter/logicmonitorexporter/README.md b/exporter/logicmonitorexporter/README.md new file mode 100644 index 000000000000..f1ae24b5b1fd --- /dev/null +++ b/exporter/logicmonitorexporter/README.md @@ -0,0 +1,41 @@ +# LogicMonitor Exporter +This exporter supports sending logs and traces data to [Logicmonitor](https://www.logicmonitor.com/). + +## Configuration Options +The following configuration options are supported: + +`url (required)`: The address to send logs and traces\ +`apitoken` : API Token of Logicmonitor\ +`headers`: Headers of POST requests\ +`log_batching_enabled`(default = true) : The flag to enable/disable batching of logs\ +`log_batching_interval`(default = 10s) : The time interval for batching of logs + +## Prerequisite: +Below environment variable must be provided + +| Key | Value | +| ------ | ------ | +| LOGICMONITOR_ACCOUNT | Company name | + +## Example +Ingestion through API Token + +```yaml + exporters: + logicmonitor: + url: "https://.logicmonitor.com/rest" + apitoken: + access_id: "" + access_key: "" +``` +OR + +Ingestion through Bearer token + +```yaml + exporters: + logicmonitor: + url: "https://.logicmonitor.com/rest" + headers: + Authorization: Bearer +``` \ No newline at end of file diff --git a/exporter/logicmonitorexporter/authenticator.go b/exporter/logicmonitorexporter/authenticator.go new file mode 100644 index 000000000000..379f88b40cf0 --- /dev/null +++ b/exporter/logicmonitorexporter/authenticator.go @@ -0,0 +1,150 @@ +// 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 logicmonitorexporter // import "github.com/open-telemetry/opentelemetry-collector-contrib/exporter/logicmonitorexporter" + +import ( + "crypto/hmac" + "crypto/sha256" + "encoding/base64" + "encoding/hex" + "fmt" + "os" + "strconv" + "strings" + "time" +) + +// LMAuthenticator is used for authenticating requests to Logicmonitor platform +type LMAuthenticator struct { + Config *Config +} + +// GetCredentials implements AuthProvider interface (https://github.com/logicmonitor/lm-data-sdk-go/blob/b135130a6cb411007cb4f8866966f00c94b7c63a/model/authprovider.go#L3) +func (a LMAuthenticator) GetCredentials(method, uri string, body []byte) string { + // Fetches token from config file, if present + // OR reads token from environment variable + authToken := getToken(a.Config.APIToken, a.Config.Headers) + if authToken.accessID != "" && authToken.accessKey != "" { + return generateLMv1Token(method, authToken.accessID, authToken.accessKey, body, uri).String() + } else if authToken.bearerToken != "" { + return authToken.bearerToken + } + return "" +} + +func getAccessToken(apitoken map[string]string) (string, string, bool) { + accessID, accessKey := "", "" + for k, v := range apitoken { + if strings.EqualFold(k, "access_id") { + accessID = v + } else if strings.EqualFold(k, "access_key") { + accessKey = v + } + } + if accessID != "" && accessKey != "" { + return accessID, accessKey, true + } + return "", "", false +} + +func getBearerToken(headers map[string]string) (string, bool) { + bearerToken := "" + for k, v := range headers { + if strings.EqualFold(k, "authorization") { + bearerToken = strings.Split(v, " ")[1] + return bearerToken, true + } + } + return "", false +} + +type AuthToken struct { + accessID string + accessKey string + bearerToken string +} + +func getToken(apiToken, headers map[string]string) AuthToken { + accessID, accessKey, ok := getAccessToken(apiToken) + if !ok { + accessID = os.Getenv("LOGICMONITOR_ACCESS_ID") + accessKey = os.Getenv("LOGICMONITOR_ACCESS_KEY") + } + bearerToken, ok := getBearerToken(headers) + if !ok { + bearerToken = os.Getenv("LOGICMONITOR_BEARER_TOKEN") + } + authToken := AuthToken{ + accessID: accessID, + accessKey: accessKey, + bearerToken: bearerToken, + } + return authToken +} + +type Lmv1Token struct { + AccessID string + Signature string + Epoch time.Time +} + +func (t *Lmv1Token) String() string { + builder := strings.Builder{} + appendSignature := func(s string) { + if _, err := builder.WriteString(s); err != nil { + fmt.Println(err) //TODO: print err in place of panic + } + } + appendSignature("LMv1 ") + appendSignature(t.AccessID) + appendSignature(":") + appendSignature(t.Signature) + appendSignature(":") + appendSignature(strconv.FormatInt(t.Epoch.UnixNano()/1000000, 10)) + + return builder.String() +} + +// GenerateLMv1Token generates LMv1 Token +func generateLMv1Token(method string, accessID string, accessKey string, body []byte, resourcePath string) *Lmv1Token { + + epochTime := time.Now() + epoch := strconv.FormatInt(epochTime.UnixNano()/1000000, 10) + + methodUpper := strings.ToUpper(method) + + h := hmac.New(sha256.New, []byte(accessKey)) + + writeOrPanic := func(bs []byte) { + if _, err := h.Write(bs); err != nil { + fmt.Println(err) //TODO: print err in place of panic + } + } + writeOrPanic([]byte(methodUpper)) + writeOrPanic([]byte(epoch)) + if body != nil { + writeOrPanic(body) + } + writeOrPanic([]byte(resourcePath)) + + hash := h.Sum(nil) + hexString := hex.EncodeToString(hash) + signature := base64.StdEncoding.EncodeToString([]byte(hexString)) + return &Lmv1Token{ + AccessID: accessID, + Signature: signature, + Epoch: epochTime, + } +} diff --git a/exporter/logicmonitorexporter/authenticator_test.go b/exporter/logicmonitorexporter/authenticator_test.go new file mode 100644 index 000000000000..0baace70944d --- /dev/null +++ b/exporter/logicmonitorexporter/authenticator_test.go @@ -0,0 +1,85 @@ +// 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 logicmonitorexporter + +import ( + "testing" +) + +func TestGetCredentials(t *testing.T) { + tests := []struct { + name string + auth LMAuthenticator + wantErr bool + }{ + { + "Get Credentials: LMv1 Config", + LMAuthenticator{ + Config: &Config{ + APIToken: map[string]string{"access_id": "testid", "access_key": "testkey"}, + }, + }, + false, + }, + { + "Get Credentials: Bearer Config", + LMAuthenticator{ + Config: &Config{ + Headers: map[string]string{"Authorization": "Bearer bearervalue"}, + }, + }, + false, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + t.Setenv("LOGICMONITOR_ACCOUNT", "localdev") + cred := tt.auth.GetCredentials("GET", "/to/path", []byte("")) + if cred == "" { + t.Errorf("GetCredentials() no credentials found..") + return + } + }) + } + +} + +func TestGetCredentials_BearerTokenEnv(t *testing.T) { + t.Setenv("LOGICMONITOR_ACCOUNT", "localdev") + t.Setenv("LOGICMONITOR_BEARER_TOKEN", "Bearer newbearertoken") + lmauth := LMAuthenticator{ + Config: &Config{}, + } + cred := lmauth.GetCredentials("GET", "/to/path", []byte("")) + if cred == "" { + t.Errorf("GetCredentials() no credentials found..") + return + } +} + +func TestGetCredentials_APITokenEnv(t *testing.T) { + t.Setenv("LOGICMONITOR_ACCOUNT", "localdev") + t.Setenv("LOGICMONITOR_ACCESS_ID", "newaccessid") + t.Setenv("LOGICMONITOR_ACCESS_KEY", "newaccesskey") + lmauth := LMAuthenticator{ + Config: &Config{}, + } + cred := lmauth.GetCredentials("GET", "/to/path", []byte("")) + if cred == "" { + t.Errorf("GetCredentials() no credentials found..") + return + } +} diff --git a/exporter/logicmonitorexporter/config.go b/exporter/logicmonitorexporter/config.go new file mode 100644 index 000000000000..42d224be547f --- /dev/null +++ b/exporter/logicmonitorexporter/config.go @@ -0,0 +1,69 @@ +// 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 logicmonitorexporter // import "github.com/open-telemetry/opentelemetry-collector-contrib/exporter/logicmonitorexporter" + +import ( + "fmt" + "net/url" + "time" + + "go.opentelemetry.io/collector/config" + "go.opentelemetry.io/collector/config/confighttp" + "go.opentelemetry.io/collector/exporter/exporterhelper" + + "github.com/open-telemetry/opentelemetry-collector-contrib/pkg/resourcetotelemetry" +) + +// Config defines configuration for Logic Monitor exporter. +type Config struct { + config.ExporterSettings `mapstructure:",squash"` + + confighttp.HTTPClientSettings `mapstructure:",squash"` + + exporterhelper.QueueSettings `mapstructure:"sending_queue"` + exporterhelper.RetrySettings `mapstructure:"retry_on_failure"` + ResourceToTelemetrySettings resourcetotelemetry.Settings `mapstructure:"resource_to_telemetry_conversion"` + + // ApiToken of LM Platform + APIToken map[string]string `mapstructure:"apitoken"` + + // URL on which the logs/traces should be forwarded + URL string `mapstructure:"url"` + + // Headers for HTTP requests + Headers map[string]string `mapstructure:"headers"` + + // Batching enabled for logs + LogBatchingEnabled bool `mapstructure:"log_batching_enabled"` + + // Batching interval for logs + LogBatchingInterval time.Duration `mapstructure:"log_batching_interval"` +} + +func (c *Config) Validate() error { + if c.URL == "" { + return fmt.Errorf("URL should not be empty") + } + + u, err := url.Parse(c.URL) + if err != nil || u.Scheme == "" || u.Host == "" { + return fmt.Errorf("URL must be valid") + } + + if c.LogBatchingInterval < MinLogBatchInterval { + return fmt.Errorf("Minimum log batching interval should be " + MinLogBatchInterval.String()) + } + return nil +} diff --git a/exporter/logicmonitorexporter/config_test.go b/exporter/logicmonitorexporter/config_test.go new file mode 100644 index 000000000000..b354117ef674 --- /dev/null +++ b/exporter/logicmonitorexporter/config_test.go @@ -0,0 +1,82 @@ +// 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 logicmonitorexporter + +import ( + "testing" + "time" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestConfigValidation(t *testing.T) { + testcases := []struct { + name string + cfg *Config + expectedErr string + }{ + { + name: "empty URL", + cfg: &Config{ + URL: "", + }, + expectedErr: "URL should not be empty", + }, + { + name: "missing http scheme", + cfg: &Config{ + URL: "test.com/dummy", + }, + expectedErr: "URL must be valid", + }, + { + name: "invalid url format", + cfg: &Config{ + URL: "#$#%54345fdsrerw", + }, + expectedErr: "URL must be valid", + }, + { + name: "valid config", + cfg: &Config{ + URL: "http://validurl.com/rest", + LogBatchingInterval: 200 * time.Millisecond, + }, + }, + { + name: "minimum batching interval", + cfg: &Config{ + URL: "http://validurl.com/rest", + LogBatchingInterval: 20 * time.Millisecond, + }, + expectedErr: "Minimum log batching interval should be 30ms", + }, + } + + for _, tc := range testcases { + t.Run(tc.name, func(t *testing.T) { + + err := tc.cfg.Validate() + + if tc.expectedErr == "" { + assert.NoError(t, err) + } else { + require.NotNil(t, err) + assert.EqualError(t, err, tc.expectedErr) + } + }) + } +} diff --git a/exporter/logicmonitorexporter/constants.go b/exporter/logicmonitorexporter/constants.go new file mode 100644 index 000000000000..7b8d7159e9e5 --- /dev/null +++ b/exporter/logicmonitorexporter/constants.go @@ -0,0 +1,24 @@ +// 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 logicmonitorexporter // import "github.com/open-telemetry/opentelemetry-collector-contrib/exporter/logicmonitorexporter" + +import "time" + +const ( + DefaultLogBatchingEnabled = true + DefaultLogBatchingInterval = 10 * time.Second + MinLogBatchInterval = 30 * time.Millisecond + Version3 = "3" +) diff --git a/exporter/logicmonitorexporter/factory.go b/exporter/logicmonitorexporter/factory.go new file mode 100644 index 000000000000..2771e3187a64 --- /dev/null +++ b/exporter/logicmonitorexporter/factory.go @@ -0,0 +1,87 @@ +// 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 logicmonitorexporter // import "github.com/open-telemetry/opentelemetry-collector-contrib/exporter/logicmonitorexporter" + +import ( + "context" + + "go.opentelemetry.io/collector/component" + "go.opentelemetry.io/collector/config" + "go.opentelemetry.io/collector/consumer" + "go.opentelemetry.io/collector/exporter/exporterhelper" +) + +const ( + // The value of "type" key in configuration. + typeStr = "logicmonitor" + // The stability level of the exporter. + stability = component.StabilityLevelBeta +) + +// NewFactory creates a LogicMonitor exporter factory +func NewFactory() component.ExporterFactory { + return component.NewExporterFactory( + typeStr, + createDefaultConfig, + component.WithTracesExporter(createTracesExporter, stability), + component.WithLogsExporter(createLogsExporter, stability), + ) +} + +func createDefaultConfig() config.Exporter { + return &Config{ + ExporterSettings: config.NewExporterSettings(config.NewComponentID(typeStr)), + LogBatchingEnabled: DefaultLogBatchingEnabled, + LogBatchingInterval: DefaultLogBatchingInterval, + } +} + +func createTracesExporter( + ctx context.Context, + set component.ExporterCreateSettings, + c config.Exporter, +) (component.TracesExporter, error) { + cfg := c.(*Config) + oce, err := newTracesExporter(cfg, set) + if err != nil { + return nil, err + } + + return exporterhelper.NewTracesExporter( + ctx, + set, + cfg, + oce.pushTraces, + exporterhelper.WithCapabilities(consumer.Capabilities{MutatesData: false}), + exporterhelper.WithRetry(cfg.RetrySettings), + exporterhelper.WithQueue(cfg.QueueSettings)) +} + +func createLogsExporter(ctx context.Context, set component.ExporterCreateSettings, cfg config.Exporter) (component.LogsExporter, error) { + oce, err := newLogsExporter(cfg, set.Logger) + if err != nil { + return nil, err + } + c := cfg.(*Config) + + return exporterhelper.NewLogsExporter( + ctx, + set, + cfg, + oce.PushLogData, + exporterhelper.WithQueue(c.QueueSettings), + exporterhelper.WithRetry(c.RetrySettings), + ) +} diff --git a/exporter/logicmonitorexporter/factory_test.go b/exporter/logicmonitorexporter/factory_test.go new file mode 100644 index 000000000000..316239e5c214 --- /dev/null +++ b/exporter/logicmonitorexporter/factory_test.go @@ -0,0 +1,94 @@ +// 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 logicmonitorexporter + +import ( + "context" + "testing" + + "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/config/confighttp" + "go.opentelemetry.io/collector/config/configtest" + "go.opentelemetry.io/collector/config/configtls" +) + +// Test that the factory creates the default configuration +func TestCreateDefaultConfig(t *testing.T) { + factory := NewFactory() + cfg := factory.CreateDefaultConfig() + + assert.Equal(t, &Config{ + ExporterSettings: config.NewExporterSettings(config.NewComponentID(typeStr)), + LogBatchingEnabled: DefaultLogBatchingEnabled, + LogBatchingInterval: DefaultLogBatchingInterval, + }, cfg, "failed to create default config") + + assert.NoError(t, configtest.CheckConfigStruct(cfg)) +} + +func TestCreateTracesExporter(t *testing.T) { + endpoint := "http://" + GetAvailableLocalAddress(t) + tests := []struct { + name string + config Config + wantErr bool + }{ + { + name: "Error scenario", + config: Config{ + URL: "&(*)8#RE/48df$#rest", + }, + wantErr: true, + }, + { + name: "Non Error scenario", + config: Config{ + ExporterSettings: config.NewExporterSettings(config.NewComponentID(typeStr)), + HTTPClientSettings: confighttp.HTTPClientSettings{ + Endpoint: endpoint, + TLSSetting: configtls.TLSClientSetting{ + Insecure: false, + }, + }, + }, + wantErr: false, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + t.Setenv("LOGICMONITOR_ACCOUNT", "localdev") + factory := NewFactory() + set := componenttest.NewNopExporterCreateSettings() + _, err := factory.CreateTracesExporter(context.Background(), set, &tt.config) + if (err != nil) != tt.wantErr { + t.Errorf("CreateTracesExporter() error = %v, wantErr %v", err, tt.wantErr) + } + }) + } +} + +func TestCreateLogsExporter(t *testing.T) { + factory := NewFactory() + cfg := factory.CreateDefaultConfig().(*Config) + set := componenttest.NewNopExporterCreateSettings() + t.Setenv("LOGICMONITOR_ACCOUNT", "localdev") + oexp, err := factory.CreateLogsExporter(context.Background(), set, cfg) + require.Nil(t, err) + require.NotNil(t, oexp) +} diff --git a/exporter/logicmonitorexporter/go.mod b/exporter/logicmonitorexporter/go.mod new file mode 100644 index 000000000000..153f5e99e76a --- /dev/null +++ b/exporter/logicmonitorexporter/go.mod @@ -0,0 +1,51 @@ +module github.com/open-telemetry/opentelemetry-collector-contrib/exporter/logicmonitorexporter + +go 1.18 + +require ( + github.com/logicmonitor/lm-data-sdk-go v0.5.0 + github.com/open-telemetry/opentelemetry-collector-contrib/pkg/resourcetotelemetry v0.64.0 + github.com/stretchr/testify v1.8.1 + go.opentelemetry.io/collector v0.64.0 + go.opentelemetry.io/collector/pdata v0.64.0 + go.uber.org/zap v1.23.0 + google.golang.org/genproto v0.0.0-20220915135415-7fd63a7952de + google.golang.org/protobuf v1.28.1 +) + +require ( + github.com/cenkalti/backoff/v4 v4.1.3 // indirect + github.com/davecgh/go-spew v1.1.1 // indirect + github.com/felixge/httpsnoop v1.0.3 // indirect + github.com/go-logr/logr v1.2.3 // indirect + github.com/go-logr/stdr v1.2.2 // indirect + github.com/gogo/protobuf v1.3.2 // indirect + github.com/golang/protobuf v1.5.2 // indirect + github.com/golang/snappy v0.0.4 // indirect + github.com/google/uuid v1.3.0 // indirect + github.com/json-iterator/go v1.1.12 // indirect + github.com/klauspost/compress v1.15.12 // indirect + github.com/knadh/koanf v1.4.4 // 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/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect + github.com/modern-go/reflect2 v1.0.2 // indirect + github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/rogpeppe/go-internal v1.9.0 // indirect + github.com/rs/cors v1.8.2 // indirect + go.opencensus.io v0.24.0 // indirect + go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.36.4 // indirect + go.opentelemetry.io/otel v1.11.1 // indirect + go.opentelemetry.io/otel/metric v0.33.0 // indirect + go.opentelemetry.io/otel/trace v1.11.1 // indirect + go.uber.org/atomic v1.10.0 // indirect + go.uber.org/multierr v1.8.0 // indirect + golang.org/x/net v0.0.0-20220909164309-bea034e7d591 // indirect + golang.org/x/sys v0.0.0-20220919091848-fb04ddd9f9c8 // indirect + golang.org/x/text v0.4.0 // indirect + google.golang.org/grpc v1.50.1 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect +) + +replace github.com/open-telemetry/opentelemetry-collector-contrib/pkg/resourcetotelemetry => ../../pkg/resourcetotelemetry diff --git a/exporter/logicmonitorexporter/go.sum b/exporter/logicmonitorexporter/go.sum new file mode 100644 index 000000000000..b9eff90e016a --- /dev/null +++ b/exporter/logicmonitorexporter/go.sum @@ -0,0 +1,475 @@ +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= +contrib.go.opencensus.io/exporter/prometheus v0.4.2 h1:sqfsYl5GIY/L570iT+l93ehxaWJs2/OwXtiWwew3oAg= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= +github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= +github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= +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/armon/go-radix v1.0.0/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.3.0 h1:ip6w0uFQkncKQ979AypyG0ER7mqUSBdKLOgAle/AT8A= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= +github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +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/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE= +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/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= +github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= +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/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= +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.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= +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/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU= +github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M= +github.com/felixge/httpsnoop v1.0.3 h1:s/nj+GCswXYzN5v2DpNMuMQYe+0DDwt5WVCU6CWBdXk= +github.com/felixge/httpsnoop v1.0.3/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= +github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= +github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= +github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= +github.com/go-kit/log v0.2.1 h1:MRVx0/zhvdseW+Gza6N9rVzU/IVzaeE1SFI4raAhmBU= +github.com/go-ldap/ldap v3.0.2+incompatible/go.mod h1:qfd9rJvER9Q0/D/Sqn1DfHRoBp40uXYvFoEVrNEPqRc= +github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= +github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= +github.com/go-logfmt/logfmt v0.5.1 h1:otpy5pqBCBZ1ng9RQ0dPu4PN7ba75Y/aA+UpowDyNVA= +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-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/go-test/deep v1.0.2-0.20181118220953-042da051cf31/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA= +github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +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/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/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +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/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE= +github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= +github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= +github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= +github.com/hashicorp/consul/api v1.13.0/go.mod h1:ZlVrynguJKcYr54zGaDbaL3fOvKC9m72FhPvA8T35KQ= +github.com/hashicorp/consul/sdk v0.8.0/go.mod h1:GBvyrGALthsZObzUGsfgHZQDXjg4lOjagTIwIR1vPms= +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-hclog v0.12.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= +github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= +github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= +github.com/hashicorp/go-multierror v1.1.0/go.mod h1:spPvp8C1qA32ftKqdAHm4hHTbPw+vmowP0z+KUhOZdA= +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-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8= +github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU= +github.com/hashicorp/go-sockaddr v1.0.2/go.mod h1:rB4wwRAUzs07qva3c5SdrY/NEtAUjGlgmH/UkBUC97A= +github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= +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/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= +github.com/hashicorp/mdns v1.0.4/go.mod h1:mtBihi+LeNXGtG8L9dX59gAEa12BDtBQSp4v/YAJqrc= +github.com/hashicorp/memberlist v0.3.0/go.mod h1:MS2lj3INKhZjWNqd3N0m3J+Jxf3DAOnAH9VT3Sh9MUE= +github.com/hashicorp/serf v0.9.6/go.mod h1:TXZNMjZQijwlDvp+r0b63xZ45H7JmCmgg4gpTwn9UV4= +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/hjson/hjson-go/v4 v4.0.0 h1:wlm6IYYqHjOdXH1gHev4VoXCaW20HdQAGCxdOEEg2cs= +github.com/hjson/hjson-go/v4 v4.0.0/go.mod h1:KaYt3bTw3zhBjYqnXkYywcYctk0A2nxeEFTse3rH13E= +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/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= +github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= +github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= +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.12 h1:YClS/PImqYbn+UILDnqxQCZ3RehC9N318SU3kElDUEM= +github.com/klauspost/compress v1.15.12/go.mod h1:QPwzmACJjUTFsnSHH934V6woptycfrDDJnH7hvFVbGM= +github.com/knadh/koanf v1.4.4 h1:d2jY5nCCeoaiqvEKSBW9rEc93EfNy/XWgWsSB3j7JEA= +github.com/knadh/koanf v1.4.4/go.mod h1:Hgyjp4y8v44hpZtPzs7JZfRAW5AhN7KfZcwv1RYggDs= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +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 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/logicmonitor/lm-data-sdk-go v0.5.0 h1:TFmXsvCOZmp0jOaJys13UKk8BTdcZ06GIuxhIV0O43g= +github.com/logicmonitor/lm-data-sdk-go v0.5.0/go.mod h1:dzWezgvavPjocqpt5KX94/0K4Fsmop8wMinRB293S48= +github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= +github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= +github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84= +github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/miekg/dns v1.1.26/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso= +github.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJysuI= +github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= +github.com/mitchellh/cli v1.1.0/go.mod h1:xcISNoH86gajksDmfB23e/pu+B+GeFRMYmoHXxx3xhI= +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 v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +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/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= +github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +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/open-telemetry/opentelemetry-collector-contrib/internal/coreinternal v0.64.0 h1:q/eqvFPeeAxZ+By7v7kZCboH0Qd8SlGoZhSJm0+Ep7I= +github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= +github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= +github.com/pelletier/go-toml v1.7.0 h1:7utD74fnzVc/cpcyy8sjrlFr5vYpypUixARcHIMIGuI= +github.com/pelletier/go-toml v1.7.0/go.mod h1:vwGMzjaWMwyfHwgIBhI2YUM4fB6nL6lVAvS1LBMMhTE= +github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +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/posener/complete v1.2.3/go.mod h1:WZIdtGGp+qx0sLrYKtIRAruyNpv6hFCicSgv7Sy7s/s= +github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= +github.com/prometheus/client_golang v1.11.1/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= +github.com/prometheus/client_golang v1.13.1 h1:3gMjIY2+/hzmqhtUC/aQNYldJA6DtH3CgQvwS+02K1c= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.3.0 h1:UBgGFHqYdG/TPFD1B1ogZywDqEkwp3fBMvqdiQ7Xew4= +github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= +github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc= +github.com/prometheus/common v0.37.0 h1:ccBbHCgIiT9uSoFY0vX8H3zsNR5eLt17/RQLUvn8pXE= +github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= +github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= +github.com/prometheus/procfs v0.8.0 h1:ODq8ZFEaYeCaZOJlZZdJA2AbQR98dSHSM1KW/You5mo= +github.com/prometheus/statsd_exporter v0.22.7 h1:7Pji/i2GuhK6Lu7DHrtTkFmNBCudCPT1pX2CziuyQR0= +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.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= +github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= +github.com/rs/cors v1.8.2 h1:KCooALfAYGs415Cwu5ABvv9n9509fSiG5SQJn/AQo4U= +github.com/rs/cors v1.8.2/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU= +github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= +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/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= +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/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +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.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= +github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +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.etcd.io/etcd/api/v3 v3.5.4/go.mod h1:5GB2vv4A4AOn3yk7MftYGHkUfGtDHnEraIjym4dYz5A= +go.etcd.io/etcd/client/pkg/v3 v3.5.4/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g= +go.etcd.io/etcd/client/v3 v3.5.4/go.mod h1:ZaRkVgBZC+L+dLCjTcF1hRXpgZXQPOvnA/Ak/gq3kiY= +go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= +go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= +go.opentelemetry.io/collector v0.64.0 h1:ebYzuWsyysz95HQwOw/r+GVRJSt7xn8kYdJTyg0XgfQ= +go.opentelemetry.io/collector v0.64.0/go.mod h1:yZzWgFxIgd17G/mQO9UbFT5gj8dCyY/Oqw1bDEEGR5E= +go.opentelemetry.io/collector/pdata v0.64.0 h1:Mx0ZawbR5F0WyUPCGB1EYsCJYsEj0iJBqX+hm3CFH40= +go.opentelemetry.io/collector/pdata v0.64.0/go.mod h1:IzvXUGQml2mrnvdb8zIlEW3qQs9oFLdD2hLwJdZ+pek= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.36.4 h1:aUEBEdCa6iamGzg6fuYxDA8ThxvOG240mAvWDU+XLio= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.36.4/go.mod h1:l2MdsbKTocpPS5nQZscqTR9jd8u96VYZdcpF8Sye7mA= +go.opentelemetry.io/otel v1.11.1 h1:4WLLAmcfkmDk2ukNXJyq3/kiz/3UzCaYq6PskJsaou4= +go.opentelemetry.io/otel v1.11.1/go.mod h1:1nNhXBbWSD0nsL38H6btgnFN2k4i0sNLHNNMZMSbUGE= +go.opentelemetry.io/otel/exporters/prometheus v0.33.0 h1:xXhPj7SLKWU5/Zd4Hxmd+X1C4jdmvc0Xy+kvjFx2z60= +go.opentelemetry.io/otel/metric v0.33.0 h1:xQAyl7uGEYvrLAiV/09iTJlp1pZnQ9Wl793qbVvED1E= +go.opentelemetry.io/otel/metric v0.33.0/go.mod h1:QlTYc+EnYNq/M2mNk1qDDMRLpqCOj2f/r5c7Fd5FYaI= +go.opentelemetry.io/otel/sdk v1.11.1 h1:F7KmQgoHljhUuJyA+9BiU+EkJfyX5nVVF4wyzWZpKxs= +go.opentelemetry.io/otel/sdk/metric v0.33.0 h1:oTqyWfksgKoJmbrs2q7O7ahkJzt+Ipekihf8vhpa9qo= +go.opentelemetry.io/otel/trace v1.11.1 h1:ofxdnzsNrGBYXbP7t7zpUK281+go5rF7dvdIZXF8gdQ= +go.opentelemetry.io/otel/trace v1.11.1/go.mod h1:f/Q9G7vzk5u91PhbmKbg1Qn0rzH1LJ4vbPHFGkTPtOk= +go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +go.uber.org/atomic v1.10.0 h1:9qC72Qh0+3MqyJbAn8YU5xVq1frD8bn3JtD2oXtafVQ= +go.uber.org/atomic v1.10.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= +go.uber.org/goleak v1.1.11 h1:wy28qYRKZgnJTxGxvye5/wgWr1EKjmUDGYox5mGlRlI= +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.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo= +go.uber.org/zap v1.23.0 h1:OjGQ5KQDEUawVHxNwQgPpiypGHOxo2mNZsOqTak4fFY= +go.uber.org/zap v1.23.0/go.mod h1:D+nX8jyLsMHMYrln8A0rJjFt/T/9/bGgIhAqxv5URuY= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392/go.mod h1:/lpIB1dKB+9EgE3H3cr1v9wB50oz8l4C4h62xy7jSTY= +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-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +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-20181114220301-adae6a3d119a/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-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190923162816-aa69164e4478/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-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +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-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= +golang.org/x/net v0.0.0-20210410081132-afb366fc7cd1/go.mod h1:9tjilg8BloeKEkVJvy7fQ90B1CfIiPueXVOjqfkSzI8= +golang.org/x/net v0.0.0-20220909164309-bea034e7d591 h1:D0B/7al0LLrVC8aWF4+oxpv/m8bc7ViFfVS8/gXGdqI= +golang.org/x/net v0.0.0-20220909164309-bea034e7d591/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= +golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +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-20201207232520-09787c993a3a/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-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/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-20190222072716-a9d3bda3a223/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-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190922100055-0a153f010e69/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200124204421-9fbb57f87de9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/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-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/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-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220919091848-fb04ddd9f9c8 h1:h+EGohizhe9XlX18rfpa8k8RAc5XyaeamM+0VHRd4lc= +golang.org/x/sys v0.0.0-20220919091848-fb04ddd9f9c8/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.2/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.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.4.0 h1:BrVqGRd7+k1DiOgtnFvAkoQEWQvBc25ouMJM6429SFg= +golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +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-20190907020128-2ca718005c18/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +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.2/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/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-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= +google.golang.org/genproto v0.0.0-20220915135415-7fd63a7952de h1:5ANeKFmGdtiputJJYeUVg8nTGA/1bEirx4CgzcnPSx8= +google.golang.org/genproto v0.0.0-20220915135415-7fd63a7952de/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo= +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.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= +google.golang.org/grpc v1.50.1 h1:DS/BukOZWp8s6p4Dt/tOaJaTQyPyOoCcrjroHuCeLzY= +google.golang.org/grpc v1.50.1/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= +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.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w= +google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= +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-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/square/go-jose.v2 v2.3.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +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.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.3.0/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/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/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= +sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc= diff --git a/exporter/logicmonitorexporter/logs_exporter.go b/exporter/logicmonitorexporter/logs_exporter.go new file mode 100644 index 000000000000..dc7e4d1a0077 --- /dev/null +++ b/exporter/logicmonitorexporter/logs_exporter.go @@ -0,0 +1,134 @@ +// 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 logicmonitorexporter // import "github.com/open-telemetry/opentelemetry-collector-contrib/exporter/logicmonitorexporter" + +import ( + "context" + "fmt" + + "github.com/logicmonitor/lm-data-sdk-go/api/logs" + "go.opentelemetry.io/collector/config" + "go.opentelemetry.io/collector/pdata/pcommon" + "go.opentelemetry.io/collector/pdata/plog" + "go.uber.org/zap" +) + +type logExporter struct { + config *Config + logger *zap.Logger + logIngestClient *logs.LMLogIngest +} + +const ( + hostname = "hostname" + hostnameProperty = "system.hostname" +) + +// Create new logs exporter +func newLogsExporter(cfg config.Exporter, logger *zap.Logger) (*logExporter, error) { + oCfg := cfg.(*Config) + + isBatchEnabled := oCfg.LogBatchingEnabled + batchInterval := oCfg.LogBatchingInterval + + if batchInterval < MinLogBatchInterval { + return nil, fmt.Errorf("Minimum batching interval should be " + MinLogBatchInterval.String()) + } + + var options []logs.Option + if isBatchEnabled { + options = []logs.Option{ + logs.WithLogBatchingInterval(batchInterval), + } + } + + auth := LMAuthenticator{ + Config: oCfg, + } + options = append(options, logs.WithAuthentication(auth)) + + lli, err := logs.NewLMLogIngest(context.Background(), options...) + if err != nil { + return nil, err + } + return &logExporter{ + config: oCfg, + logger: logger, + logIngestClient: lli, + }, nil +} + +func (e *logExporter) PushLogData(ctx context.Context, lg plog.Logs) (er error) { + resourceLogs := lg.ResourceLogs() + for i := 0; i < resourceLogs.Len(); i++ { + resourceLog := resourceLogs.At(i) + libraryLogs := resourceLog.ScopeLogs() + for j := 0; j < libraryLogs.Len(); j++ { + libraryLog := libraryLogs.At(j) + logs := libraryLog.LogRecords() + for k := 0; k < logs.Len(); k++ { + logMetadataMap := make(map[string]string) + resourceMapperMap := make(map[string]string) + log := logs.At(k) + // Copying resource attributes to log attributes + resourceLog.Resource().Attributes().Range(func(k string, v pcommon.Value) bool { + logAttributes := log.Attributes() + e.mergeAttributes(k, v, logAttributes) + return true + }) + attributesMap := log.Attributes() + attributesMap.Range(func(key string, value pcommon.Value) bool { + if key == hostname { + resourceMapperMap[hostnameProperty] = value.StringVal() + } + logMetadataMap[key] = value.StringVal() + return true + }) + err := e.logIngestClient.SendLogs(ctx, log.Body().StringVal(), resourceMapperMap, logMetadataMap) + if err != nil { + e.logger.Error("error while sending logs ", zap.Error(err)) + } + } + } + } + return nil +} + +func (e *logExporter) mergeAttributes(k string, value pcommon.Value, logAttr pcommon.Map) { + switch value.Type() { + case pcommon.ValueTypeInt: + logAttr.PutInt(k, value.IntVal()) + case pcommon.ValueTypeBool: + logAttr.PutBool(k, value.BoolVal()) + case pcommon.ValueTypeDouble: + logAttr.PutDouble(k, value.DoubleVal()) + case pcommon.ValueTypeString: + logAttr.PutString(k, value.StringVal()) + case pcommon.ValueTypeMap: + values := map[string]interface{}{} + value.MapVal().Range(func(k string, v pcommon.Value) bool { + values[k] = v + return true + }) + case pcommon.ValueTypeSlice: + arrayVal := value.SliceVal() + values := make([]interface{}, arrayVal.Len()) + for i := 0; i < arrayVal.Len(); i++ { + values[i] = arrayVal.At(i) + } + default: + e.logger.Debug("Unhandled value type", zap.String("type", value.Type().String())) + } +} diff --git a/exporter/logicmonitorexporter/logs_exporter_test.go b/exporter/logicmonitorexporter/logs_exporter_test.go new file mode 100644 index 000000000000..7c8620a8b940 --- /dev/null +++ b/exporter/logicmonitorexporter/logs_exporter_test.go @@ -0,0 +1,186 @@ +// 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 logicmonitorexporter + +import ( + "context" + "encoding/json" + "fmt" + "net/http" + "net/http/httptest" + "testing" + "time" + + "github.com/logicmonitor/lm-data-sdk-go/api/logs" + "go.opentelemetry.io/collector/config" + "go.opentelemetry.io/collector/pdata/pcommon" + "go.opentelemetry.io/collector/pdata/plog" + "go.uber.org/zap" +) + +func Test_NewLogsExporter(t *testing.T) { + + type args struct { + config *Config + logger *zap.Logger + } + tests := []struct { + name string + args args + wantErr bool + }{ + { + "NewLogExporter: success", + args{ + config: &Config{ + ExporterSettings: config.NewExporterSettings(config.NewComponentID("logicmonitor")), + URL: "https://test.logicmonitor.com/rest", + APIToken: map[string]string{"access_id": "testid", "access_key": "testkey"}, + LogBatchingEnabled: true, + LogBatchingInterval: 50 * time.Millisecond, + }, + logger: zap.NewNop(), + }, + false, + }, + { + "NewLogExporter: fail", + args{ + config: &Config{ + ExporterSettings: config.NewExporterSettings(config.NewComponentID("logicmonitor")), + URL: "https://test.logicmonitor.com/rest", + APIToken: map[string]string{"access_id": "testid", "access_key": "testkey"}, + LogBatchingEnabled: true, + LogBatchingInterval: 20 * time.Millisecond, + }, + logger: zap.NewNop(), + }, + true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + t.Setenv("LOGICMONITOR_ACCOUNT", "localdev") + _, err := newLogsExporter(tt.args.config, tt.args.logger) + if (err != nil) != tt.wantErr { + t.Errorf("newLogsExporter() error = %v, wantErr %v", err, tt.wantErr) + return + } + }) + } +} + +type Response struct { + Success bool `json:"success"` + Message string `json:"message"` +} + +func TestPushLogData(t *testing.T) { + + ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + + response := Response{ + Success: true, + Message: "Logs exported successfully", + } + body, _ := json.Marshal(response) + _, _ = w.Write(body) + })) + + type args struct { + ctx context.Context + lg plog.Logs + } + + type fields struct { + batchEnabled bool + config *Config + logger *zap.Logger + } + + cfg := &Config{ + URL: ts.URL, + APIToken: map[string]string{"access_id": "testid", "access_key": "testkey"}, + } + + tests := []struct { + name string + fields fields + args args + }{ + { + name: "Send Log data", + fields: fields{ + batchEnabled: false, + logger: zap.NewNop(), + config: cfg, + }, + args: args{ + ctx: context.Background(), + lg: createLogData(1), + }, + }, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + t.Setenv("LOGICMONITOR_ACCOUNT", "localdev") + var options []logs.Option + if test.fields.batchEnabled { + options = []logs.Option{ + logs.WithLogBatchingInterval(1 * time.Second), + } + } + client, err := logs.NewLMLogIngest(context.Background(), options...) + fmt.Println("Error while creating log ingest client: ", err) + e := &logExporter{ + logger: test.fields.logger, + config: test.fields.config, + logIngestClient: client, + } + err = e.PushLogData(test.args.ctx, test.args.lg) + if err != nil { + t.Errorf("logicmonitorexporter.PushLogsData() error = %v", err) + return + } + }) + } +} + +func createLogData(numberOfLogs int) plog.Logs { + logs := plog.NewLogs() + logs.ResourceLogs().AppendEmpty() // Add an empty ResourceLogs + rl := logs.ResourceLogs().AppendEmpty() + rl.Resource().Attributes().PutString("service.name", "myapp") + rl.Resource().Attributes().PutInt("http.statusCode", 200) + rl.Resource().Attributes().PutBool("isTest", true) + rl.Resource().Attributes().PutDouble("value", 20.00) + rl.Resource().Attributes().PutEmptySlice("values") + rl.Resource().Attributes().PutEmptyMap("valueMap") + rl.ScopeLogs().AppendEmpty() // Add an empty InstrumentationLibraryLogs + ill := rl.ScopeLogs().AppendEmpty() + + for i := 0; i < numberOfLogs; i++ { + ts := pcommon.Timestamp(int64(i) * time.Millisecond.Nanoseconds()) + logRecord := ill.LogRecords().AppendEmpty() + logRecord.Body().SetStringVal("mylog") + logRecord.Attributes().PutString("my-label", "myapp-type") + logRecord.Attributes().PutString("custom", "custom") + logRecord.SetTimestamp(ts) + } + ill.LogRecords().AppendEmpty() + + return logs +} diff --git a/exporter/logicmonitorexporter/session.go b/exporter/logicmonitorexporter/session.go new file mode 100644 index 000000000000..6ebd96ac50fe --- /dev/null +++ b/exporter/logicmonitorexporter/session.go @@ -0,0 +1,185 @@ +// 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 logicmonitorexporter // import "github.com/open-telemetry/opentelemetry-collector-contrib/exporter/logicmonitorexporter" + +import ( + "bytes" + "context" + "crypto/tls" + "fmt" + "io" + "log" + "net/http" + "os" + "strings" + "time" +) + +const ( + httpPrefix = "https://" + platformEP = ".logicmonitor.com" +) + +type accountInfo interface { + name() string + id() string + token(method string, payload []byte, uri string) string +} + +type lmv1Account struct { + accountName string + accessID string + accessKey string +} + +func (a lmv1Account) name() string { + return a.accountName +} + +func (a lmv1Account) id() string { + return a.accessID +} + +func (a lmv1Account) token(method string, data []byte, uri string) string { + return generateLMv1Token(method, a.accessID, a.accessKey, data, uri).String() +} + +type bearerAccount struct { + accountName string + key string +} + +func (b bearerAccount) name() string { + return b.accountName +} + +func (b bearerAccount) id() string { + return strings.Split(b.key, ":")[0] +} + +func (b bearerAccount) token(method string, data []byte, uri string) string { + return "Bearer " + b.key +} + +type HTTPClient interface { + MakeRequest(ctx context.Context, version, method, baseURI, uri, configURL string, timeout time.Duration, pBytes *bytes.Buffer, headers map[string]string) (*APIResponse, error) + GetContent(url string) (*http.Response, error) +} + +// LMhttpClient http client builder for LogicMonitor +type LMhttpClient struct { + client *http.Client + aInfo accountInfo +} + +type APIResponse struct { + Body []byte + Headers http.Header + StatusCode int + ContentLength int64 +} + +// NewLMHTTPClient returns HttpClient and bearer/lmv1 account +func NewLMHTTPClient(apitoken, headers map[string]string) HTTPClient { + var aInfo accountInfo + account := os.Getenv("LOGICMONITOR_ACCOUNT") + if account == "" { + log.Fatal("LOGICMONITOR_ACCOUNT environment not set") + } + + // Fetches token from config file, if present + // OR reads token from environment variable + authToken := getToken(apitoken, headers) + if authToken.accessID != "" && authToken.accessKey != "" { + aInfo = lmv1Account{accountName: account, accessID: authToken.accessID, accessKey: authToken.accessKey} + } else if authToken.bearerToken != "" { + aInfo = bearerAccount{accountName: account, key: authToken.bearerToken} + } + + transport := http.DefaultTransport.(*http.Transport).Clone() + transport.TLSClientConfig = &tls.Config{InsecureSkipVerify: false, MinVersion: tls.VersionTLS12} + clientTransport := (http.RoundTripper)(transport) + httpClient := &http.Client{Transport: clientTransport, Timeout: 0} + return &LMhttpClient{httpClient, aInfo} +} + +// MakeRequest over LMHTTPClient +func (c *LMhttpClient) MakeRequest(ctx context.Context, version, method, baseURI, uri, configURL string, timeout time.Duration, pBytes *bytes.Buffer, headers map[string]string) (*APIResponse, error) { + if c.client == nil { + log.Fatal("Session not established") + } + var req *http.Request + var err error + var fullURL string + var account string + + if c.aInfo == nil { + account = os.Getenv("LOGICMONITOR_ACCOUNT") + } else { + account = c.aInfo.name() + } + if configURL != "" { + fullURL = configURL + uri + } else { + fullURL = httpPrefix + account + platformEP + baseURI + uri + } + + if pBytes == nil { + pBytes = bytes.NewBuffer(nil) + } + req, err = http.NewRequest(method, fullURL, pBytes) + if err != nil { + return nil, fmt.Errorf("creation of request failed with error %w", err) + } + + reqCtx, cancel := context.WithTimeout(ctx, timeout) + defer cancel() + req = req.WithContext(reqCtx) + req.Header.Set("X-version", version) + req.Header.Set("x-logicmonitor-account", account) + req.Header.Set("Content-Type", "application/json") + req.Header.Set("Accept", "application/json") + if c.aInfo != nil { + if method == http.MethodPost && pBytes != nil { + req.Header.Set("Authorization", c.aInfo.token(method, pBytes.Bytes(), uri)) + } else { + req.Header.Set("Authorization", c.aInfo.token(method, nil, uri)) + } + } + for key, value := range headers { + req.Header.Set(key, value) + } + resp, err := c.client.Do(req) + if err != nil { + return nil, fmt.Errorf("sending request to %s failed with error %w", fullURL, err) + } + + defer resp.Body.Close() + body, err := io.ReadAll(resp.Body) + if err != nil { + return nil, fmt.Errorf("error reading response %s, failed with error %w", fullURL, err) + } + apiResp := APIResponse{body, resp.Header, resp.StatusCode, resp.ContentLength} + return &apiResp, nil +} + +// GetContent downloads the content from specified url +func (c *LMhttpClient) GetContent(url string) (*http.Response, error) { + req, err := http.NewRequest(http.MethodGet, url, nil) + if err != nil { + return nil, err + } + return c.client.Do(req) +} diff --git a/exporter/logicmonitorexporter/session_test.go b/exporter/logicmonitorexporter/session_test.go new file mode 100644 index 000000000000..90952294d3e5 --- /dev/null +++ b/exporter/logicmonitorexporter/session_test.go @@ -0,0 +1,470 @@ +// 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 logicmonitorexporter + +import ( + "bytes" + "context" + "net/http" + "net/http/httptest" + "strings" + "testing" + "time" +) + +func Test_lmv1Account_name(t *testing.T) { + type fields struct { + accountName string + accessID string + accessKey string + } + tests := []struct { + name string + fields fields + want string + }{ + // TODO: Add test cases. + { + "Blank arguments test", + fields{ + "", + "", + "", + }, + "", + }, + { + "Sample test case-1", + fields{ + "localdev", + "1", + "NDhOQ1R0ck5MXl9CcjZpNThhezZ1ZmNJW1s0Q2d+ZUZjfXYtbjN1bn1GM0ppSVZ+ayVKXng1bTRmMjRkNms3KA==", + }, + "localdev", + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + a := lmv1Account{ + accountName: tt.fields.accountName, + accessID: tt.fields.accessID, + accessKey: tt.fields.accessKey, + } + if got := a.name(); got != tt.want { + t.Errorf("lmv1Account.name() = %v, want %v", got, tt.want) + } + }) + } +} + +func Test_lmv1Account_id(t *testing.T) { + type fields struct { + accountName string + accessID string + accessKey string + } + tests := []struct { + name string + fields fields + want string + }{ + // TODO: Add test cases. + { + "Blank arguments test", + fields{ + "", + "", + "", + }, + "", + }, + { + "Sample test case-1", + fields{ + "localdev", + "1", + "NDhOQ1R0ck5MXl9CcjZpNThhezZ1ZmNJW1s0Q2d+ZUZjfXYtbjN1bn1GM0ppSVZ+ayVKXng1bTRmMjRkNms3KA==", + }, + "1", + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + a := lmv1Account{ + accountName: tt.fields.accountName, + accessID: tt.fields.accessID, + accessKey: tt.fields.accessKey, + } + if got := a.id(); got != tt.want { + t.Errorf("lmv1Account.id() = %v, want %v", got, tt.want) + } + }) + } +} + +func Test_lmv1Account_token(t *testing.T) { + type fields struct { + accountName string + accessID string + accessKey string + } + type args struct { + method string + data []byte + uri string + } + tests := []struct { + name string + fields fields + args args + wantErr bool + }{ + // TODO: Add test cases. + { + "Sample test case-1", + fields{ + "localdev", + "MButz9r3iiz458G354nh", + "Up83q}-6eCLGH95nU6R2)7EJIAE%bahE)L5G7qf9", + }, + args{ + http.MethodGet, + []byte(""), + "https://localdev.logicmonitor.com/santaba/rest/ping", + }, + false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + a := lmv1Account{ + accountName: tt.fields.accountName, + accessID: tt.fields.accessID, + accessKey: tt.fields.accessKey, + } + token := a.token(tt.args.method, tt.args.data, tt.args.uri) + + res := strings.Split(token, ":") + if res[0] != "LMv1 "+tt.fields.accessID { + t.Error("a.token() generates wrong LMv1 token") + } + }) + } +} + +func Test_bearerAccount_name(t *testing.T) { + type fields struct { + accountName string + key string + } + tests := []struct { + name string + fields fields + want string + }{ + // TODO: Add test cases. + { + "Blank arguments test", + fields{ + "", + "", + }, + "", + }, + { + "Sample test case-1", + fields{ + "localdev", + "Q2s4NDl6S3gzcjdaZmpZdEM5bks6M0V6UEtMZG5zT1p4aWNpc0Z5YnVTdz09", + }, + "localdev", + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + b := bearerAccount{ + accountName: tt.fields.accountName, + key: tt.fields.key, + } + if got := b.name(); got != tt.want { + t.Errorf("bearerAccount.name() = %v, want %v", got, tt.want) + } + }) + } +} + +func Test_bearerAccount_id(t *testing.T) { + type fields struct { + accountName string + key string + } + tests := []struct { + name string + fields fields + want string + }{ + // TODO: Add test cases. + { + "Blank arguments test", + fields{ + "", + "", + }, + "", + }, + { + "Sample test case-1", + fields{ + "localdev", + "g96qSJx5E83P84xNcfUa:(+CH7s3R[Q4a4_EDyFv3N74=t)Eu^9G_8{J5UcR^", + }, + "g96qSJx5E83P84xNcfUa", + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + b := bearerAccount{ + accountName: tt.fields.accountName, + key: tt.fields.key, + } + if got := b.id(); got != tt.want { + t.Errorf("bearerAccount.id() = %v, want %v", got, tt.want) + } + }) + } +} + +func Test_bearerAccount_token(t *testing.T) { + type fields struct { + accountName string + key string + } + type args struct { + method string + data []byte + uri string + } + tests := []struct { + name string + fields fields + args args + want string + }{ + // TODO: Add test cases. + { + "Blank arguments test", + fields{ + "", + "", + }, + args{ + "", + []byte(""), + "", + }, + "Bearer ", + }, + { + "Sample test case-1", + fields{ + "localdev", + "g96qSJx5E83P84xNcfUa:(+CH7s3R[Q4a4_EDyFv3N74=t)Eu^9G_8{J5UcR^", + }, + args{ + "", + []byte(""), + "", + }, + "Bearer g96qSJx5E83P84xNcfUa:(+CH7s3R[Q4a4_EDyFv3N74=t)Eu^9G_8{J5UcR^", + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + b := bearerAccount{ + accountName: tt.fields.accountName, + key: tt.fields.key, + } + if got := b.token(tt.args.method, tt.args.data, tt.args.uri); got != tt.want { + t.Errorf("bearerAccount.token() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestNewLMHTTPClient_APItoken(t *testing.T) { + + t.Setenv("LOGICMONITOR_ACCOUNT", "localdev") + apitoken := make(map[string]string) + apitoken["access_id"] = "GvGs48z52b25L648C3s8" + apitoken["access_key"] = "~wfe=5E)Y844[xj}h=xCBPAn]{9mb}3mk_nd4[n[" + + if got := NewLMHTTPClient(apitoken, nil); got == nil { + t.Errorf("Got NewLMHTTPClient() = %v , want `not nil`", got) + } +} + +func TestNewLMHTTPClient_BearerToken(t *testing.T) { + t.Setenv("LOGICMONITOR_ACCOUNT", "localdev") + headers := make(map[string]string) + headers["Authorization"] = "Bearer UkpnODZhdWs0V0JZd1V4ODUzUXk6azdRbzFJOHBFWFJSVDBJYXNOamVmUT09" + if got := NewLMHTTPClient(nil, headers); got == nil { + t.Errorf("Got NewLMHTTPClient() = %v , want `not nil`", got) + } +} + +func TestNewLMHTTPClient_BearerTokenEnv(t *testing.T) { + t.Setenv("LOGICMONITOR_ACCOUNT", "localdev") + t.Setenv("LOGICMONITOR_BEARER_TOKEN", "newbearertoken") + if got := NewLMHTTPClient(nil, nil); got == nil { + t.Errorf("Got NewLMHTTPClient() = %v , want `not nil`", got) + } +} + +func TestNewLMHTTPClient_APITokenEnv(t *testing.T) { + t.Setenv("LOGICMONITOR_ACCOUNT", "localdev") + t.Setenv("LOGICMONITOR_ACCESS_ID", "newaccessid") + t.Setenv("LOGICMONITOR_ACCESS_KEY", "newaccesskey") + if got := NewLMHTTPClient(nil, nil); got == nil { + t.Errorf("Got NewLMHTTPClient() = %v , want `not nil`", got) + } +} + +func TestLMhttpClient_MakeRequest(t *testing.T) { + + m := http.NewServeMux() + m.HandleFunc("/ping", func(w http.ResponseWriter, r *http.Request) { + _, _ = w.Write([]byte(`200OK1634019117032`)) + }) + ts := httptest.NewServer(m) + + a := lmv1Account{ + accountName: "localdev", + accessID: "GvGs48z52b25L648C3s8", + accessKey: "~wfe=5E)Y844[xj}h=xCBPAn]{9mb}3mk_nd4[n[", + } + + type args struct { + version string + method string + baseURI string + uri string + configURL string + timeout time.Duration + pBytes *bytes.Buffer + headers map[string]string + } + tests := []struct { + name string + mockHTTPClient LMhttpClient + args args + wantErr bool + }{ + { + "Make Request: http.MethodGet", + LMhttpClient{ + client: ts.Client(), + aInfo: a, + }, + args{ + "3", + http.MethodGet, + "", + "", + ts.URL, + 5 * time.Second, + nil, + nil, + }, + false, + }, + { + "Make Request : http.MethodPost", + LMhttpClient{ + client: ts.Client(), + aInfo: a, + }, + args{ + "3", + http.MethodPost, + "", + "", + ts.URL, + 5 * time.Second, + bytes.NewBuffer([]byte("body")), + nil, + }, + false, + }, + { + "Make Request : Error", + LMhttpClient{ + client: ts.Client(), + }, + args{ + "3", + http.MethodPost, + "/santaba/api", + "/ping", + "", + 5 * time.Second, + bytes.NewBuffer([]byte("body")), + nil, + }, + true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + + _, err := tt.mockHTTPClient.MakeRequest(context.Background(), tt.args.version, tt.args.method, tt.args.baseURI, tt.args.uri, tt.args.configURL, tt.args.timeout, tt.args.pBytes, tt.args.headers) + if (err != nil) != tt.wantErr { + t.Errorf("LMhttpClient.MakeRequest() error = %v, wantErr %v", err, tt.wantErr) + return + } + }) + } +} + +func TestLMhttpClient_GetContent(t *testing.T) { + + type args struct { + url string + } + tests := []struct { + name string + args args + wantErr bool + }{ + // TODO: Add test cases + { + "Get content", + args{ + "http://google.com", + }, + false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + t.Setenv("LOGICMONITOR_ACCOUNT", "localdev") + hc := NewLMHTTPClient(nil, nil) + _, err := hc.GetContent(tt.args.url) + if (err != nil) != tt.wantErr { + t.Errorf("LMhttpClient.GetContent() error = %v, wantErr %v", err, tt.wantErr) + return + } + }) + } +} diff --git a/exporter/logicmonitorexporter/testdata/config_logs.yaml b/exporter/logicmonitorexporter/testdata/config_logs.yaml new file mode 100644 index 000000000000..b18cd49e4e36 --- /dev/null +++ b/exporter/logicmonitorexporter/testdata/config_logs.yaml @@ -0,0 +1,16 @@ +receivers: + fluentforward: + endpoint: 127.0.0.1:8006 +processors: + batch: +exporters: + logicmonitor: + url: https://example.logicmonitor.com/rest + apitoken: + access_id: "xyz" + access_key: "abcdefg123" +service: + pipelines: + logs: + receivers: [ fluentforward ] + exporters: [ logicmonitor ] \ No newline at end of file diff --git a/exporter/logicmonitorexporter/testdata/config_traces.yaml b/exporter/logicmonitorexporter/testdata/config_traces.yaml new file mode 100644 index 000000000000..a5a29c046736 --- /dev/null +++ b/exporter/logicmonitorexporter/testdata/config_traces.yaml @@ -0,0 +1,22 @@ +receivers: + otlp: + protocols: + http: + grpc: +processors: + batch: +exporters: + logicmonitor: + url: https://example.logicmonitor.com/rest + apitoken: + access_id: "xyz" + access_key: "abcdefg123" + logging: + logLevel: debug + +service: + pipelines: + traces: + receivers : [ otlp ] + processors: [ batch ] + exporters : [ logicmonitor ] \ No newline at end of file diff --git a/exporter/logicmonitorexporter/traces_exporter.go b/exporter/logicmonitorexporter/traces_exporter.go new file mode 100644 index 000000000000..7948b02155df --- /dev/null +++ b/exporter/logicmonitorexporter/traces_exporter.go @@ -0,0 +1,169 @@ +// 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 logicmonitorexporter // import "github.com/open-telemetry/opentelemetry-collector-contrib/exporter/logicmonitorexporter" + +import ( + "bytes" + "context" + "fmt" + "io" + "net/http" + "net/url" + "runtime" + "strconv" + "time" + + "go.opentelemetry.io/collector/component" + "go.opentelemetry.io/collector/consumer/consumererror" + "go.opentelemetry.io/collector/exporter/exporterhelper" + "go.opentelemetry.io/collector/pdata/ptrace" + "go.opentelemetry.io/collector/pdata/ptrace/ptraceotlp" + "go.uber.org/zap" + "google.golang.org/genproto/googleapis/rpc/status" + "google.golang.org/protobuf/proto" +) + +type tracesExporter struct { + // Input configuration. + config *Config + client HTTPClient + logger *zap.Logger + settings component.TelemetrySettings + // Default user-agent header. + userAgent string +} + +const ( + headerRetryAfter = "Retry-After" + maxHTTPResponseReadBytes = 64 * 1024 + traceIngestURI = "/api/v1/traces" + traceBaseURI = "/rest" +) + +// Create new traces exporter +func newTracesExporter(cfg *Config, set component.ExporterCreateSettings) (*tracesExporter, error) { + + if cfg.URL != "" { + u, err := url.Parse(cfg.URL) + if err != nil || u.Scheme == "" || u.Host == "" { + return nil, fmt.Errorf("endpoint must be a valid URL") + } + } + + newClient := NewLMHTTPClient(cfg.APIToken, cfg.Headers) + + userAgent := fmt.Sprintf("%s/%s (%s/%s)", + set.BuildInfo.Description, set.BuildInfo.Version, runtime.GOOS, runtime.GOARCH) + + return &tracesExporter{ + config: cfg, + logger: set.Logger, + client: newClient, + userAgent: userAgent, + settings: set.TelemetrySettings, + }, nil +} + +func (e *tracesExporter) pushTraces(ctx context.Context, td ptrace.Traces) error { + tr := ptraceotlp.NewRequestFromTraces(td) + request, err := tr.MarshalProto() + if err != nil { + return consumererror.NewPermanent(err) + } + + return e.export(ctx, e.config.URL, request) +} + +func (e *tracesExporter) export(ctx context.Context, url string, request []byte) error { + headers := make(map[string]string) + headers["Content-Type"] = "application/x-protobuf" + + resp, err := e.client.MakeRequest(ctx, Version3, http.MethodPost, traceBaseURI, traceIngestURI, url, 5*time.Second, bytes.NewBuffer(request), headers) + if err != nil { + return err + } + defer func() { + // Discard any remaining response body when we are done reading. + _, _ = io.CopyN(io.Discard, bytes.NewReader(resp.Body), maxHTTPResponseReadBytes) // nolint:errcheck + }() + + if resp.StatusCode >= 200 && resp.StatusCode <= 299 { + // Request is successful. + return nil + } + + respStatus := readResponse(resp) + + // Format the error message. Use the status if it is present in the response. + var formattedErr error + if respStatus != nil { + formattedErr = fmt.Errorf( + "error exporting items, request to %s responded with HTTP Status Code %d, Message=%s, Details=%v", + url+traceIngestURI, resp.StatusCode, respStatus.Message, respStatus.Details) + } else { + formattedErr = fmt.Errorf( + "error exporting items, request to %s responded with HTTP Status Code %d", + url+traceIngestURI, resp.StatusCode) + } + + // Check if the server is overwhelmed. + // See spec https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/protocol/otlp.md#throttling-1 + if resp.StatusCode == http.StatusTooManyRequests || resp.StatusCode == http.StatusServiceUnavailable { + // Fallback to 0 if the Retry-After header is not present. This will trigger the + // default backoff policy by our caller (retry handler). + retryAfter := 0 + if val := resp.Headers.Get(headerRetryAfter); val != "" { + if seconds, err2 := strconv.Atoi(val); err2 == nil { + retryAfter = seconds + } + } + // Indicate to our caller to pause for the specified number of seconds. + return exporterhelper.NewThrottleRetry(formattedErr, time.Duration(retryAfter)*time.Second) + } + + if resp.StatusCode == http.StatusBadRequest { + // Report the failure as permanent if the server thinks the request is malformed. + return consumererror.NewPermanent(formattedErr) + } + + // All other errors are retryable, so don't wrap them in consumererror.Permanent(). + return formattedErr +} + +// Read the response and decode the status.Status from the body. +// Returns nil if the response is empty or cannot be decoded. +func readResponse(resp *APIResponse) *status.Status { + var respStatus *status.Status + if resp.StatusCode >= 400 && resp.StatusCode <= 599 { + // Request failed. Read the body. OTLP spec says: + // "Response body for all HTTP 4xx and HTTP 5xx responses MUST be a + // Protobuf-encoded Status message that describes the problem." + maxRead := resp.ContentLength + if maxRead == -1 || maxRead > maxHTTPResponseReadBytes { + maxRead = maxHTTPResponseReadBytes + } + respBytes := make([]byte, maxRead) + n, err := io.ReadFull(bytes.NewReader(resp.Body), respBytes) + if err == nil && n > 0 { + // Decode it as Status struct. See https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/protocol/otlp.md#failures + respStatus = &status.Status{} + err = proto.Unmarshal(respBytes, respStatus) + if err != nil { + respStatus = nil + } + } + } + return respStatus +} diff --git a/exporter/logicmonitorexporter/traces_exporter_test.go b/exporter/logicmonitorexporter/traces_exporter_test.go new file mode 100644 index 000000000000..e75df363163c --- /dev/null +++ b/exporter/logicmonitorexporter/traces_exporter_test.go @@ -0,0 +1,567 @@ +// 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 logicmonitorexporter + +import ( + "bytes" + "context" + "encoding/json" + "fmt" + "io" + "net" + "net/http" + "net/http/httptest" + "testing" + "time" + + "go.opentelemetry.io/collector/component" + "go.opentelemetry.io/collector/component/componenttest" + "go.opentelemetry.io/collector/config" + "go.opentelemetry.io/collector/pdata/pcommon" + "go.opentelemetry.io/collector/pdata/ptrace" + "go.uber.org/zap" +) + +var ( + TestSpanStartTime = time.Date(2020, 2, 11, 20, 26, 12, 321, time.UTC) + TestSpanStartTimestamp = pcommon.NewTimestampFromTime(TestSpanStartTime) + + TestSpanEventTime = time.Date(2020, 2, 11, 20, 26, 13, 123, time.UTC) + TestSpanEventTimestamp = pcommon.NewTimestampFromTime(TestSpanEventTime) + + TestSpanEndTime = time.Date(2020, 2, 11, 20, 26, 13, 789, time.UTC) + TestSpanEndTimestamp = pcommon.NewTimestampFromTime(TestSpanEndTime) +) + +type tracesResponse struct { + Ok int `json:"linesOk"` + Invalid int `json:"linesInvalid"` + Error string `json:"error"` +} + +type TraceMockHTTPClient struct { + URL string + Client *http.Client + IsTimeoutSet bool + RequestTimeOut time.Duration +} + +func Test_newTraceExporter(t *testing.T) { + + type args struct { + config *Config + logger *zap.Logger + buildInfo component.BuildInfo + } + tests := []struct { + name string + args args + wantErr bool + }{ + { + "newTracesExporter: success", + args{ + config: &Config{ + ExporterSettings: config.NewExporterSettings(config.NewComponentID("logicmonitor")), + APIToken: map[string]string{"access_id": "testid", "access_key": "testkey"}, + }, + logger: zap.NewNop(), + buildInfo: component.BuildInfo{}, + }, + false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + t.Setenv("LOGICMONITOR_ACCOUNT", "localdev") + set := componenttest.NewNopExporterCreateSettings() + _, err := newTracesExporter(tt.args.config, set) + if (err != nil) != tt.wantErr { + t.Errorf("newTracesExporter() error = %v, wantErr %v", err, tt.wantErr) + return + } + }) + } +} + +func Test_newTraceExporter_InvalidURL(t *testing.T) { + + type args struct { + config *Config + logger *zap.Logger + buildInfo component.BuildInfo + } + tests := []struct { + name string + args args + wantErr bool + }{ + { + "newTracesExporter: success", + args{ + config: &Config{ + ExporterSettings: config.NewExporterSettings(config.NewComponentID("logicmonitor")), + APIToken: map[string]string{"access_id": "testid", "access_key": "testkey"}, + }, + logger: zap.NewNop(), + buildInfo: component.BuildInfo{}, + }, + true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + t.Setenv("LOGICMONITOR_ACCOUNT", "localdev") + tt.args.config.URL = "&(*)8#RE/48df$#rest" + set := componenttest.NewNopExporterCreateSettings() + _, err := newTracesExporter(tt.args.config, set) + if (err != nil) != tt.wantErr { + t.Errorf("newTracesExporter() error = %v, wantErr %v", err, tt.wantErr) + return + } + }) + } +} + +func (c *TraceMockHTTPClient) MakeRequest(ctx context.Context, version, method, baseURI, uri, configURL string, timeout time.Duration, pBytes *bytes.Buffer, headers map[string]string) (*APIResponse, error) { + var err error + var req *http.Request + var body []byte + + if method == http.MethodPost && pBytes != nil { + req, err = http.NewRequest(method, c.URL, pBytes) + } else { + req, err = http.NewRequest(method, c.URL, nil) + } + if err != nil { + return nil, fmt.Errorf("creation of request failed with error %w", err) + } + + ctx, cancel := context.WithTimeout(ctx, timeout) + + if c.IsTimeoutSet { + ctx, cancel = context.WithTimeout(req.Context(), c.RequestTimeOut) + } + + defer cancel() + req = req.WithContext(ctx) + + req.Header.Set("X-version", version) + req.Header.Set("Content-Type", "application/json") + req.Header.Set("Accept", "application/json") + for key, value := range headers { + req.Header.Set(key, value) + } + resp, err := c.Client.Do(req) + + if err != nil { + return nil, fmt.Errorf("sending request to %s failed with error %w", c.URL, err) + } + defer resp.Body.Close() + + body, err = io.ReadAll(resp.Body) + if err != nil { + return nil, fmt.Errorf("error reading response %s, failed with error %w", c.URL, err) + } + apiResp := APIResponse{body, resp.Header, resp.StatusCode, resp.ContentLength} + return &apiResp, nil +} + +func (c *TraceMockHTTPClient) GetContent(url string) (*http.Response, error) { + return nil, nil +} + +func TestPushTraceData(t *testing.T) { + + ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + + response := tracesResponse{ + Ok: 0, + Invalid: 0, + } + body, _ := json.Marshal(response) + _, _ = w.Write(body) + })) + + type args struct { + ctx context.Context + trace ptrace.Traces + } + + type fields struct { + // Input configuration. + config *Config + logger *zap.Logger + client HTTPClient + } + + cfg := &Config{ + URL: ts.URL, + APIToken: map[string]string{"access_id": "testid", "access_key": "testkey"}, + } + + tests := []struct { + name string + fields fields + args args + }{ + { + name: "Send Trace data: Successful", + fields: fields{ + logger: zap.NewNop(), + config: cfg, + client: &TraceMockHTTPClient{ + URL: ts.URL, + Client: ts.Client(), + }, + }, + args: args{ + ctx: context.Background(), + trace: GenerateTracesOneSpan(), + }, + }, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + + e := &tracesExporter{ + logger: test.fields.logger, + config: test.fields.config, + client: test.fields.client, + } + + err := e.pushTraces(test.args.ctx, test.args.trace) + + if err != nil { + t.Errorf("traces exporter.pushTraces() error = %v", err) + return + } + }) + } +} + +func TestTraceExport_ConnectionRefused(t *testing.T) { + + ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(http.StatusOK) + })) + + type args struct { + ctx context.Context + trace ptrace.Traces + } + + type fields struct { + // Input configuration. + config *Config + logger *zap.Logger + client HTTPClient + } + + cfg := &Config{ + APIToken: map[string]string{"access_id": "testid", "access_key": "testkey"}, + } + + test := struct { + name string + fields fields + args args + wantErr bool + }{ + name: "Send Trace data: Connection Refused", + fields: fields{ + logger: zap.NewNop(), + config: cfg, + client: &TraceMockHTTPClient{ + URL: "http://test.logicmonitor.com/v1/traces", + Client: ts.Client(), + }, + }, + args: args{ + ctx: context.Background(), + trace: GenerateTracesOneSpan(), + }, + wantErr: true, + } + + t.Run(test.name, func(t *testing.T) { + + e := &tracesExporter{ + logger: test.fields.logger, + config: test.fields.config, + client: test.fields.client, + } + err := e.pushTraces(test.args.ctx, test.args.trace) + if (err != nil) != test.wantErr { + t.Errorf("traceexporter.pushTrace() error = %v, wantErr %v", err, test.wantErr) + return + } + }) +} + +func TestPushTraceData_404(t *testing.T) { + + ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(http.StatusNotFound) + })) + + type args struct { + ctx context.Context + trace ptrace.Traces + } + + type fields struct { + // Input configuration. + config *Config + logger *zap.Logger + client HTTPClient + } + + cfg := &Config{ + URL: ts.URL, + APIToken: map[string]string{"access_id": "testid", "access_key": "testkey"}, + } + + tests := []struct { + name string + fields fields + args args + wantErr bool + }{ + { + name: "Send Trace data: Error", + fields: fields{ + logger: zap.NewNop(), + config: cfg, + client: &TraceMockHTTPClient{ + URL: ts.URL, + Client: ts.Client(), + }, + }, + args: args{ + ctx: context.Background(), + trace: GenerateTracesOneSpan(), + }, + wantErr: true, + }, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + + e := &tracesExporter{ + logger: test.fields.logger, + config: test.fields.config, + client: test.fields.client, + } + + err := e.pushTraces(test.args.ctx, test.args.trace) + if (err != nil) != test.wantErr { + t.Errorf("traceexporter.pushTrace() error = %v, wantErr %v", err, test.wantErr) + return + } + }) + } +} + +func TestPushTraceData_Retry(t *testing.T) { + + ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Retry-After", "200") + w.WriteHeader(http.StatusTooManyRequests) + })) + + type args struct { + ctx context.Context + trace ptrace.Traces + } + + type fields struct { + // Input configuration. + config *Config + logger *zap.Logger + client HTTPClient + } + + cfg := &Config{ + URL: ts.URL, + APIToken: map[string]string{"access_id": "testid", "access_key": "testkey"}, + } + + tests := []struct { + name string + fields fields + args args + wantErr bool + }{ + { + name: "Send Trace data: Error", + fields: fields{ + logger: zap.NewNop(), + config: cfg, + client: &TraceMockHTTPClient{ + URL: ts.URL, + Client: ts.Client(), + }, + }, + args: args{ + ctx: context.Background(), + trace: GenerateTracesOneSpan(), + }, + wantErr: true, + }, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + + e := &tracesExporter{ + logger: test.fields.logger, + config: test.fields.config, + client: test.fields.client, + } + + err := e.pushTraces(test.args.ctx, test.args.trace) + if (err != nil) != test.wantErr { + t.Errorf("traceexporter.pushTrace() error = %v, wantErr %v", err, test.wantErr) + return + } + }) + } +} + +func TestPushTraceData_BadRequest(t *testing.T) { + + ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(http.StatusBadRequest) + _, _ = w.Write([]byte(`{"code":400,"message":"Bad Request","details":"error details"}`)) + })) + + type args struct { + ctx context.Context + trace ptrace.Traces + } + + type fields struct { + // Input configuration. + config *Config + logger *zap.Logger + client HTTPClient + } + + cfg := &Config{ + URL: ts.URL, + APIToken: map[string]string{"access_id": "testid", "access_key": "testkey"}, + } + + tests := []struct { + name string + fields fields + args args + wantErr bool + }{ + { + name: "Send Trace data: Error", + fields: fields{ + logger: zap.NewNop(), + config: cfg, + client: &TraceMockHTTPClient{ + URL: ts.URL, + Client: ts.Client(), + }, + }, + args: args{ + ctx: context.Background(), + trace: GenerateTracesOneSpan(), + }, + wantErr: true, + }, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + + e := &tracesExporter{ + logger: test.fields.logger, + config: test.fields.config, + client: test.fields.client, + } + + err := e.pushTraces(test.args.ctx, test.args.trace) + if (err != nil) != test.wantErr { + t.Errorf("traceexporter.pushTrace() error = %v, wantErr %v", err, test.wantErr) + return + } + }) + } +} + +func GetAvailableLocalAddress(t *testing.T) string { + ln, _ := net.Listen("tcp", "localhost:0") + // There is a possible race if something else takes this same port before + // the test uses it, however, that is unlikely in practice. + defer ln.Close() + return ln.Addr().String() +} + +func GenerateTracesOneSpan() ptrace.Traces { + td := GenerateTracesOneEmptyInstrumentationLibrary() + rs0ils0 := td.ResourceSpans().At(0).ScopeSpans().At(0) + fillSpanOne(rs0ils0.Spans().AppendEmpty()) + return td +} + +func GenerateTracesOneEmptyInstrumentationLibrary() ptrace.Traces { + td := GenerateTracesNoLibraries() + td.ResourceSpans().At(0).ScopeSpans().AppendEmpty() + return td +} + +func GenerateTracesOneEmptyResourceSpans() ptrace.Traces { + td := ptrace.NewTraces() + td.ResourceSpans().AppendEmpty() + return td +} + +func GenerateTracesNoLibraries() ptrace.Traces { + td := GenerateTracesOneEmptyResourceSpans() + rs0 := td.ResourceSpans().At(0) + rs0.Resource().Attributes().PutString("service.name", "uop.stage-eu-1") + rs0.Resource().Attributes().PutString("outsystems.module.version", "903386") + return td +} + +func fillSpanOne(span ptrace.Span) { + span.SetName("operationA") + span.SetStartTimestamp(TestSpanStartTimestamp) + span.SetEndTimestamp(TestSpanEndTimestamp) + span.SetDroppedAttributesCount(1) + evs := span.Events() + ev0 := evs.AppendEmpty() + ev0.SetTimestamp(TestSpanEventTimestamp) + ev0.SetName("event-with-attr") + span.Attributes().PutInt("span_index", 3) + span.Attributes().PutString("code.function", "myFunction") + ev0.SetDroppedAttributesCount(2) + ev1 := evs.AppendEmpty() + ev1.SetTimestamp(TestSpanEventTimestamp) + ev1.SetName("event") + ev1.SetDroppedAttributesCount(2) + span.SetDroppedEventsCount(1) + status := span.Status() + status.SetCode(ptrace.StatusCodeError) + status.SetMessage("status-cancelled") +} diff --git a/go.mod b/go.mod index 1879e6129203..a40a949adba8 100644 --- a/go.mod +++ b/go.mod @@ -28,6 +28,7 @@ require ( github.com/open-telemetry/opentelemetry-collector-contrib/exporter/jaegerthrifthttpexporter v0.64.0 github.com/open-telemetry/opentelemetry-collector-contrib/exporter/kafkaexporter v0.64.0 github.com/open-telemetry/opentelemetry-collector-contrib/exporter/loadbalancingexporter v0.64.0 + github.com/open-telemetry/opentelemetry-collector-contrib/exporter/logicmonitorexporter v0.64.0 github.com/open-telemetry/opentelemetry-collector-contrib/exporter/logzioexporter v0.64.0 github.com/open-telemetry/opentelemetry-collector-contrib/exporter/lokiexporter v0.64.0 github.com/open-telemetry/opentelemetry-collector-contrib/exporter/mezmoexporter v0.64.0 @@ -442,6 +443,7 @@ require ( github.com/lightstep/go-expohisto v1.0.0 // indirect github.com/linkedin/goavro/v2 v2.9.8 // indirect github.com/linode/linodego v1.8.0 // indirect + github.com/logicmonitor/lm-data-sdk-go v0.5.0 // indirect github.com/lufia/plan9stats v0.0.0-20220517141722-cf486979b281 // indirect github.com/magiconair/properties v1.8.6 // indirect github.com/mailru/easyjson v0.7.7 // indirect @@ -737,6 +739,8 @@ replace github.com/open-telemetry/opentelemetry-collector-contrib/exporter/kafka replace github.com/open-telemetry/opentelemetry-collector-contrib/exporter/loadbalancingexporter => ./exporter/loadbalancingexporter +replace github.com/open-telemetry/opentelemetry-collector-contrib/exporter/logicmonitorexporter => ./exporter/logicmonitorexporter + replace github.com/open-telemetry/opentelemetry-collector-contrib/exporter/logzioexporter => ./exporter/logzioexporter replace github.com/open-telemetry/opentelemetry-collector-contrib/exporter/lokiexporter => ./exporter/lokiexporter diff --git a/go.sum b/go.sum index 88c34b5f511e..6191a682ed43 100644 --- a/go.sum +++ b/go.sum @@ -1609,6 +1609,8 @@ github.com/linkedin/goavro/v2 v2.9.8 h1:jN50elxBsGBDGVDEKqUlDuU1cFwJ11K/yrJCBMe/ github.com/linkedin/goavro/v2 v2.9.8/go.mod h1:UgQUb2N/pmueQYH9bfqFioWxzYCZXSfF8Jw03O5sjqA= github.com/linode/linodego v1.8.0 h1:7B2UaWu6C48tZZZrtINWRElAcwzk4TLnL9USjKf3xm0= github.com/linode/linodego v1.8.0/go.mod h1:heqhl91D8QTPVm2k9qZHP78zzbOdTFLXE9NJc3bcc50= +github.com/logicmonitor/lm-data-sdk-go v0.5.0 h1:TFmXsvCOZmp0jOaJys13UKk8BTdcZ06GIuxhIV0O43g= +github.com/logicmonitor/lm-data-sdk-go v0.5.0/go.mod h1:dzWezgvavPjocqpt5KX94/0K4Fsmop8wMinRB293S48= github.com/logrusorgru/aurora v0.0.0-20181002194514-a7b3b318ed4e/go.mod h1:7rIyQOR62GCctdiQpZ/zOJlFyk6y+94wXzv6RNZgaR4= github.com/lucasb-eyer/go-colorful v1.0.2/go.mod h1:0MS4r+7BZKSJ5mw4/S5MPN+qHFF1fYclkSPilDOKW0s= github.com/lucasb-eyer/go-colorful v1.0.3/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0= diff --git a/internal/components/components.go b/internal/components/components.go index 2f1a8851d768..98b91a9b2db6 100644 --- a/internal/components/components.go +++ b/internal/components/components.go @@ -50,6 +50,7 @@ import ( "github.com/open-telemetry/opentelemetry-collector-contrib/exporter/jaegerthrifthttpexporter" "github.com/open-telemetry/opentelemetry-collector-contrib/exporter/kafkaexporter" "github.com/open-telemetry/opentelemetry-collector-contrib/exporter/loadbalancingexporter" + "github.com/open-telemetry/opentelemetry-collector-contrib/exporter/logicmonitorexporter" "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/mezmoexporter" @@ -319,6 +320,7 @@ func Components() (component.Factories, error) { kafkaexporter.NewFactory(), loadbalancingexporter.NewFactory(), loggingexporter.NewFactory(), + logicmonitorexporter.NewFactory(), logzioexporter.NewFactory(), lokiexporter.NewFactory(), mezmoexporter.NewFactory(), diff --git a/internal/components/exporters_test.go b/internal/components/exporters_test.go index 20a14f88844d..7a65de09670f 100644 --- a/internal/components/exporters_test.go +++ b/internal/components/exporters_test.go @@ -55,6 +55,7 @@ import ( "github.com/open-telemetry/opentelemetry-collector-contrib/exporter/jaegerthrifthttpexporter" "github.com/open-telemetry/opentelemetry-collector-contrib/exporter/kafkaexporter" "github.com/open-telemetry/opentelemetry-collector-contrib/exporter/loadbalancingexporter" + "github.com/open-telemetry/opentelemetry-collector-contrib/exporter/logicmonitorexporter" "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/mezmoexporter" @@ -382,6 +383,13 @@ func TestDefaultExporters(t *testing.T) { return cfg }, }, + { + exporter: "logicmonitor", + getConfigFn: func() config.Exporter { + cfg := expFactories["logicmonitor"].CreateDefaultConfig().(*logicmonitorexporter.Config) + return cfg + }, + }, { exporter: "logzio", getConfigFn: func() component.ExporterConfig { diff --git a/versions.yaml b/versions.yaml index 0b45bb52a3d1..888c719d0b6d 100644 --- a/versions.yaml +++ b/versions.yaml @@ -48,6 +48,7 @@ module-sets: - github.com/open-telemetry/opentelemetry-collector-contrib/exporter/jaegerthrifthttpexporter - github.com/open-telemetry/opentelemetry-collector-contrib/exporter/kafkaexporter - github.com/open-telemetry/opentelemetry-collector-contrib/exporter/loadbalancingexporter + - github.com/open-telemetry/opentelemetry-collector-contrib/exporter/logicmonitorexporter - 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/mezmoexporter From fb779f414893bab330cac717c78148566f1183ce Mon Sep 17 00:00:00 2001 From: Khyati Gandhi Date: Mon, 10 Oct 2022 15:20:41 +0530 Subject: [PATCH 2/9] Fixing deprecated functions --- .../logicmonitorexporter/logs_exporter.go | 20 +++++++++---------- .../logs_exporter_test.go | 2 +- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/exporter/logicmonitorexporter/logs_exporter.go b/exporter/logicmonitorexporter/logs_exporter.go index dc7e4d1a0077..0040ff262d44 100644 --- a/exporter/logicmonitorexporter/logs_exporter.go +++ b/exporter/logicmonitorexporter/logs_exporter.go @@ -91,12 +91,12 @@ func (e *logExporter) PushLogData(ctx context.Context, lg plog.Logs) (er error) attributesMap := log.Attributes() attributesMap.Range(func(key string, value pcommon.Value) bool { if key == hostname { - resourceMapperMap[hostnameProperty] = value.StringVal() + resourceMapperMap[hostnameProperty] = value.Str() } - logMetadataMap[key] = value.StringVal() + logMetadataMap[key] = value.Str() return true }) - err := e.logIngestClient.SendLogs(ctx, log.Body().StringVal(), resourceMapperMap, logMetadataMap) + err := e.logIngestClient.SendLogs(ctx, log.Body().Str(), resourceMapperMap, logMetadataMap) if err != nil { e.logger.Error("error while sending logs ", zap.Error(err)) } @@ -109,21 +109,21 @@ func (e *logExporter) PushLogData(ctx context.Context, lg plog.Logs) (er error) func (e *logExporter) mergeAttributes(k string, value pcommon.Value, logAttr pcommon.Map) { switch value.Type() { case pcommon.ValueTypeInt: - logAttr.PutInt(k, value.IntVal()) + logAttr.PutInt(k, value.Int()) case pcommon.ValueTypeBool: - logAttr.PutBool(k, value.BoolVal()) + logAttr.PutBool(k, value.Bool()) case pcommon.ValueTypeDouble: - logAttr.PutDouble(k, value.DoubleVal()) - case pcommon.ValueTypeString: - logAttr.PutString(k, value.StringVal()) + logAttr.PutDouble(k, value.Double()) + case pcommon.ValueTypeStr: + logAttr.PutString(k, value.Str()) case pcommon.ValueTypeMap: values := map[string]interface{}{} - value.MapVal().Range(func(k string, v pcommon.Value) bool { + value.Map().Range(func(k string, v pcommon.Value) bool { values[k] = v return true }) case pcommon.ValueTypeSlice: - arrayVal := value.SliceVal() + arrayVal := value.Slice() values := make([]interface{}, arrayVal.Len()) for i := 0; i < arrayVal.Len(); i++ { values[i] = arrayVal.At(i) diff --git a/exporter/logicmonitorexporter/logs_exporter_test.go b/exporter/logicmonitorexporter/logs_exporter_test.go index 7c8620a8b940..5da1506b3335 100644 --- a/exporter/logicmonitorexporter/logs_exporter_test.go +++ b/exporter/logicmonitorexporter/logs_exporter_test.go @@ -175,7 +175,7 @@ func createLogData(numberOfLogs int) plog.Logs { for i := 0; i < numberOfLogs; i++ { ts := pcommon.Timestamp(int64(i) * time.Millisecond.Nanoseconds()) logRecord := ill.LogRecords().AppendEmpty() - logRecord.Body().SetStringVal("mylog") + logRecord.Body().SetStr("mylog") logRecord.Attributes().PutString("my-label", "myapp-type") logRecord.Attributes().PutString("custom", "custom") logRecord.SetTimestamp(ts) From c448e02f76ce103dca332c925e4abeb3786f0f84 Mon Sep 17 00:00:00 2001 From: Khyati Gandhi Date: Tue, 11 Oct 2022 16:36:08 +0530 Subject: [PATCH 3/9] Moving changelog.yaml file from unreleased/ to .chloggen/ --- .../logicmonitorexporter-implementation.yaml | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 .chloggen/logicmonitorexporter-implementation.yaml diff --git a/.chloggen/logicmonitorexporter-implementation.yaml b/.chloggen/logicmonitorexporter-implementation.yaml new file mode 100644 index 000000000000..45f32730a69e --- /dev/null +++ b/.chloggen/logicmonitorexporter-implementation.yaml @@ -0,0 +1,16 @@ +# One of 'breaking', 'deprecation', 'new_component', 'enhancement', 'bug_fix' +change_type: new_component + +# The name of the component, or a single word describing the area of concern, (e.g. filelogreceiver) +component: logicmonitorexporter + +# A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`). +note: New exporter for exporting traces and logs to Logicmonitor Platform + +# One or more tracking issues related to the change +issues: [13727] + +# (Optional) One or more lines of additional information to render under the primary note. +# These lines will be padded with 2 spaces and then inserted directly into the document. +# Use pipe (|) for multiline entries. +subtext: From 0bacdc73221c85ed76d1694588808daca01d54eb Mon Sep 17 00:00:00 2001 From: Khyati Gandhi Date: Mon, 31 Oct 2022 15:18:25 +0530 Subject: [PATCH 4/9] Removed extra file from changelog --- .chloggen/logicmonitor_implementation.yaml | 16 ---------------- 1 file changed, 16 deletions(-) delete mode 100644 .chloggen/logicmonitor_implementation.yaml diff --git a/.chloggen/logicmonitor_implementation.yaml b/.chloggen/logicmonitor_implementation.yaml deleted file mode 100644 index 45f32730a69e..000000000000 --- a/.chloggen/logicmonitor_implementation.yaml +++ /dev/null @@ -1,16 +0,0 @@ -# One of 'breaking', 'deprecation', 'new_component', 'enhancement', 'bug_fix' -change_type: new_component - -# The name of the component, or a single word describing the area of concern, (e.g. filelogreceiver) -component: logicmonitorexporter - -# A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`). -note: New exporter for exporting traces and logs to Logicmonitor Platform - -# One or more tracking issues related to the change -issues: [13727] - -# (Optional) One or more lines of additional information to render under the primary note. -# These lines will be padded with 2 spaces and then inserted directly into the document. -# Use pipe (|) for multiline entries. -subtext: From 10dc4ab50c1421db541d49f1a8bb78536209125e Mon Sep 17 00:00:00 2001 From: Khyati Gandhi Date: Wed, 2 Nov 2022 16:57:34 +0530 Subject: [PATCH 5/9] Resolving errors due to deprecated function names v0.63.0 --- exporter/logicmonitorexporter/logs_exporter.go | 2 +- exporter/logicmonitorexporter/logs_exporter_test.go | 6 +++--- exporter/logicmonitorexporter/traces_exporter.go | 2 +- exporter/logicmonitorexporter/traces_exporter_test.go | 6 +++--- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/exporter/logicmonitorexporter/logs_exporter.go b/exporter/logicmonitorexporter/logs_exporter.go index 0040ff262d44..cf4ffcf06267 100644 --- a/exporter/logicmonitorexporter/logs_exporter.go +++ b/exporter/logicmonitorexporter/logs_exporter.go @@ -115,7 +115,7 @@ func (e *logExporter) mergeAttributes(k string, value pcommon.Value, logAttr pco case pcommon.ValueTypeDouble: logAttr.PutDouble(k, value.Double()) case pcommon.ValueTypeStr: - logAttr.PutString(k, value.Str()) + logAttr.PutStr(k, value.Str()) case pcommon.ValueTypeMap: values := map[string]interface{}{} value.Map().Range(func(k string, v pcommon.Value) bool { diff --git a/exporter/logicmonitorexporter/logs_exporter_test.go b/exporter/logicmonitorexporter/logs_exporter_test.go index 5da1506b3335..97cea6609da0 100644 --- a/exporter/logicmonitorexporter/logs_exporter_test.go +++ b/exporter/logicmonitorexporter/logs_exporter_test.go @@ -163,7 +163,7 @@ func createLogData(numberOfLogs int) plog.Logs { logs := plog.NewLogs() logs.ResourceLogs().AppendEmpty() // Add an empty ResourceLogs rl := logs.ResourceLogs().AppendEmpty() - rl.Resource().Attributes().PutString("service.name", "myapp") + rl.Resource().Attributes().PutStr("service.name", "myapp") rl.Resource().Attributes().PutInt("http.statusCode", 200) rl.Resource().Attributes().PutBool("isTest", true) rl.Resource().Attributes().PutDouble("value", 20.00) @@ -176,8 +176,8 @@ func createLogData(numberOfLogs int) plog.Logs { ts := pcommon.Timestamp(int64(i) * time.Millisecond.Nanoseconds()) logRecord := ill.LogRecords().AppendEmpty() logRecord.Body().SetStr("mylog") - logRecord.Attributes().PutString("my-label", "myapp-type") - logRecord.Attributes().PutString("custom", "custom") + logRecord.Attributes().PutStr("my-label", "myapp-type") + logRecord.Attributes().PutStr("custom", "custom") logRecord.SetTimestamp(ts) } ill.LogRecords().AppendEmpty() diff --git a/exporter/logicmonitorexporter/traces_exporter.go b/exporter/logicmonitorexporter/traces_exporter.go index 7948b02155df..97c42aea8071 100644 --- a/exporter/logicmonitorexporter/traces_exporter.go +++ b/exporter/logicmonitorexporter/traces_exporter.go @@ -77,7 +77,7 @@ func newTracesExporter(cfg *Config, set component.ExporterCreateSettings) (*trac } func (e *tracesExporter) pushTraces(ctx context.Context, td ptrace.Traces) error { - tr := ptraceotlp.NewRequestFromTraces(td) + tr := ptraceotlp.NewExportRequestFromTraces(td) request, err := tr.MarshalProto() if err != nil { return consumererror.NewPermanent(err) diff --git a/exporter/logicmonitorexporter/traces_exporter_test.go b/exporter/logicmonitorexporter/traces_exporter_test.go index e75df363163c..0547596cf366 100644 --- a/exporter/logicmonitorexporter/traces_exporter_test.go +++ b/exporter/logicmonitorexporter/traces_exporter_test.go @@ -539,8 +539,8 @@ func GenerateTracesOneEmptyResourceSpans() ptrace.Traces { func GenerateTracesNoLibraries() ptrace.Traces { td := GenerateTracesOneEmptyResourceSpans() rs0 := td.ResourceSpans().At(0) - rs0.Resource().Attributes().PutString("service.name", "uop.stage-eu-1") - rs0.Resource().Attributes().PutString("outsystems.module.version", "903386") + rs0.Resource().Attributes().PutStr("service.name", "uop.stage-eu-1") + rs0.Resource().Attributes().PutStr("outsystems.module.version", "903386") return td } @@ -554,7 +554,7 @@ func fillSpanOne(span ptrace.Span) { ev0.SetTimestamp(TestSpanEventTimestamp) ev0.SetName("event-with-attr") span.Attributes().PutInt("span_index", 3) - span.Attributes().PutString("code.function", "myFunction") + span.Attributes().PutStr("code.function", "myFunction") ev0.SetDroppedAttributesCount(2) ev1 := evs.AppendEmpty() ev1.SetTimestamp(TestSpanEventTimestamp) From 1a471984a2ce7f771809d2836666323865fecb4b Mon Sep 17 00:00:00 2001 From: Khyati Gandhi Date: Mon, 7 Nov 2022 12:02:33 +0530 Subject: [PATCH 6/9] Updated code owners and mod dependency --- .github/CODEOWNERS | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 984a77732fe3..a93e44c25df4 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -55,6 +55,7 @@ exporter/jaegerexporter/ @open-telemetry/collector-c exporter/jaegerthrifthttpexporter/ @open-telemetry/collector-contrib-approvers @jpkrohling @pavolloffay exporter/kafkaexporter/ @open-telemetry/collector-contrib-approvers @pavolloffay @MovieStoreGuy exporter/loadbalancingexporter/ @open-telemetry/collector-contrib-approvers @jpkrohling +exporter/logicmonitorexporter/ @open-telemetry/collector-contrib-approvers @bogdandrutu @khyatigandhi6 @avadhut123pisal exporter/logzioexporter/ @open-telemetry/collector-contrib-approvers @jkowall @Doron-Bargo @yotamloe exporter/lokiexporter/ @open-telemetry/collector-contrib-approvers @gramidt @gouthamve @jpkrohling @kovrus @mar4uk exporter/mezmoexporter/ @open-telemetry/collector-contrib-approvers @dashpole @billmeyer @gjanco @jsumners From aff0572420f63bcaad806192ac9066611f944eb3 Mon Sep 17 00:00:00 2001 From: Khyati Gandhi Date: Mon, 7 Nov 2022 17:50:35 +0530 Subject: [PATCH 7/9] add your component to the dropdown list in the issue templates --- .github/CODEOWNERS | 2 +- .github/ISSUE_TEMPLATE/bug_report.yaml | 1 + .github/ISSUE_TEMPLATE/feature_request.yaml | 1 + .github/ISSUE_TEMPLATE/other.yaml | 1 + 4 files changed, 4 insertions(+), 1 deletion(-) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index a93e44c25df4..0360699c4ea0 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -55,7 +55,7 @@ exporter/jaegerexporter/ @open-telemetry/collector-c exporter/jaegerthrifthttpexporter/ @open-telemetry/collector-contrib-approvers @jpkrohling @pavolloffay exporter/kafkaexporter/ @open-telemetry/collector-contrib-approvers @pavolloffay @MovieStoreGuy exporter/loadbalancingexporter/ @open-telemetry/collector-contrib-approvers @jpkrohling -exporter/logicmonitorexporter/ @open-telemetry/collector-contrib-approvers @bogdandrutu @khyatigandhi6 @avadhut123pisal +exporter/logicmonitorexporter/ @open-telemetry/collector-contrib-approvers @bogdandrutu @khyatigandhi6 @avadhut123pisal exporter/logzioexporter/ @open-telemetry/collector-contrib-approvers @jkowall @Doron-Bargo @yotamloe exporter/lokiexporter/ @open-telemetry/collector-contrib-approvers @gramidt @gouthamve @jpkrohling @kovrus @mar4uk exporter/mezmoexporter/ @open-telemetry/collector-contrib-approvers @dashpole @billmeyer @gjanco @jsumners diff --git a/.github/ISSUE_TEMPLATE/bug_report.yaml b/.github/ISSUE_TEMPLATE/bug_report.yaml index 051879d0f37d..01a4369e11d6 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yaml +++ b/.github/ISSUE_TEMPLATE/bug_report.yaml @@ -48,6 +48,7 @@ body: - exporter/jaegerthrifthttp - exporter/kafka - exporter/loadbalancing + - exporter/logicmonitor - exporter/logzio - exporter/loki - exporter/mezmo diff --git a/.github/ISSUE_TEMPLATE/feature_request.yaml b/.github/ISSUE_TEMPLATE/feature_request.yaml index 50e04d1bde3c..9363618e7fcd 100644 --- a/.github/ISSUE_TEMPLATE/feature_request.yaml +++ b/.github/ISSUE_TEMPLATE/feature_request.yaml @@ -42,6 +42,7 @@ body: - exporter/jaegerthrifthttp - exporter/kafka - exporter/loadbalancing + - exporter/logicmonitor - exporter/logzio - exporter/loki - exporter/mezmo diff --git a/.github/ISSUE_TEMPLATE/other.yaml b/.github/ISSUE_TEMPLATE/other.yaml index c2f7b66c6c09..1e08572a474b 100644 --- a/.github/ISSUE_TEMPLATE/other.yaml +++ b/.github/ISSUE_TEMPLATE/other.yaml @@ -42,6 +42,7 @@ body: - exporter/jaegerthrifthttp - exporter/kafka - exporter/loadbalancing + - exporter/logicmonitor - exporter/logzio - exporter/loki - exporter/mezmo From 3dfc4222dde4bd1f89a000149c36299fb34733a0 Mon Sep 17 00:00:00 2001 From: Khyati Gandhi Date: Fri, 11 Nov 2022 11:59:23 +0530 Subject: [PATCH 8/9] New version support changes --- exporter/logicmonitorexporter/factory.go | 8 ++++---- exporter/logicmonitorexporter/factory_test.go | 8 ++++---- exporter/logicmonitorexporter/go.mod | 4 ++-- exporter/logicmonitorexporter/go.sum | 8 ++++---- exporter/logicmonitorexporter/logs_exporter.go | 4 ++-- exporter/logicmonitorexporter/logs_exporter_test.go | 5 +++-- exporter/logicmonitorexporter/traces_exporter_test.go | 4 ++-- 7 files changed, 21 insertions(+), 20 deletions(-) diff --git a/exporter/logicmonitorexporter/factory.go b/exporter/logicmonitorexporter/factory.go index 2771e3187a64..7237e5f31bcc 100644 --- a/exporter/logicmonitorexporter/factory.go +++ b/exporter/logicmonitorexporter/factory.go @@ -40,9 +40,9 @@ func NewFactory() component.ExporterFactory { ) } -func createDefaultConfig() config.Exporter { +func createDefaultConfig() component.ExporterConfig { return &Config{ - ExporterSettings: config.NewExporterSettings(config.NewComponentID(typeStr)), + ExporterSettings: config.NewExporterSettings(component.NewID(typeStr)), LogBatchingEnabled: DefaultLogBatchingEnabled, LogBatchingInterval: DefaultLogBatchingInterval, } @@ -51,7 +51,7 @@ func createDefaultConfig() config.Exporter { func createTracesExporter( ctx context.Context, set component.ExporterCreateSettings, - c config.Exporter, + c component.ExporterConfig, ) (component.TracesExporter, error) { cfg := c.(*Config) oce, err := newTracesExporter(cfg, set) @@ -69,7 +69,7 @@ func createTracesExporter( exporterhelper.WithQueue(cfg.QueueSettings)) } -func createLogsExporter(ctx context.Context, set component.ExporterCreateSettings, cfg config.Exporter) (component.LogsExporter, error) { +func createLogsExporter(ctx context.Context, set component.ExporterCreateSettings, cfg component.ExporterConfig) (component.LogsExporter, error) { oce, err := newLogsExporter(cfg, set.Logger) if err != nil { return nil, err diff --git a/exporter/logicmonitorexporter/factory_test.go b/exporter/logicmonitorexporter/factory_test.go index 316239e5c214..5993b83b4a59 100644 --- a/exporter/logicmonitorexporter/factory_test.go +++ b/exporter/logicmonitorexporter/factory_test.go @@ -20,10 +20,10 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/component/componenttest" "go.opentelemetry.io/collector/config" "go.opentelemetry.io/collector/config/confighttp" - "go.opentelemetry.io/collector/config/configtest" "go.opentelemetry.io/collector/config/configtls" ) @@ -33,12 +33,12 @@ func TestCreateDefaultConfig(t *testing.T) { cfg := factory.CreateDefaultConfig() assert.Equal(t, &Config{ - ExporterSettings: config.NewExporterSettings(config.NewComponentID(typeStr)), + ExporterSettings: config.NewExporterSettings(component.NewID(typeStr)), LogBatchingEnabled: DefaultLogBatchingEnabled, LogBatchingInterval: DefaultLogBatchingInterval, }, cfg, "failed to create default config") - assert.NoError(t, configtest.CheckConfigStruct(cfg)) + assert.NoError(t, componenttest.CheckConfigStruct(cfg)) } func TestCreateTracesExporter(t *testing.T) { @@ -58,7 +58,7 @@ func TestCreateTracesExporter(t *testing.T) { { name: "Non Error scenario", config: Config{ - ExporterSettings: config.NewExporterSettings(config.NewComponentID(typeStr)), + ExporterSettings: config.NewExporterSettings(component.NewID(typeStr)), HTTPClientSettings: confighttp.HTTPClientSettings{ Endpoint: endpoint, TLSSetting: configtls.TLSClientSetting{ diff --git a/exporter/logicmonitorexporter/go.mod b/exporter/logicmonitorexporter/go.mod index 153f5e99e76a..3319c3036f5f 100644 --- a/exporter/logicmonitorexporter/go.mod +++ b/exporter/logicmonitorexporter/go.mod @@ -6,8 +6,8 @@ require ( github.com/logicmonitor/lm-data-sdk-go v0.5.0 github.com/open-telemetry/opentelemetry-collector-contrib/pkg/resourcetotelemetry v0.64.0 github.com/stretchr/testify v1.8.1 - go.opentelemetry.io/collector v0.64.0 - go.opentelemetry.io/collector/pdata v0.64.0 + go.opentelemetry.io/collector v0.64.2-0.20221110222631-20e3aac00413 + go.opentelemetry.io/collector/pdata v0.64.2-0.20221110222631-20e3aac00413 go.uber.org/zap v1.23.0 google.golang.org/genproto v0.0.0-20220915135415-7fd63a7952de google.golang.org/protobuf v1.28.1 diff --git a/exporter/logicmonitorexporter/go.sum b/exporter/logicmonitorexporter/go.sum index b9eff90e016a..c1b23fb92251 100644 --- a/exporter/logicmonitorexporter/go.sum +++ b/exporter/logicmonitorexporter/go.sum @@ -289,10 +289,10 @@ go.etcd.io/etcd/client/pkg/v3 v3.5.4/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3 go.etcd.io/etcd/client/v3 v3.5.4/go.mod h1:ZaRkVgBZC+L+dLCjTcF1hRXpgZXQPOvnA/Ak/gq3kiY= go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= -go.opentelemetry.io/collector v0.64.0 h1:ebYzuWsyysz95HQwOw/r+GVRJSt7xn8kYdJTyg0XgfQ= -go.opentelemetry.io/collector v0.64.0/go.mod h1:yZzWgFxIgd17G/mQO9UbFT5gj8dCyY/Oqw1bDEEGR5E= -go.opentelemetry.io/collector/pdata v0.64.0 h1:Mx0ZawbR5F0WyUPCGB1EYsCJYsEj0iJBqX+hm3CFH40= -go.opentelemetry.io/collector/pdata v0.64.0/go.mod h1:IzvXUGQml2mrnvdb8zIlEW3qQs9oFLdD2hLwJdZ+pek= +go.opentelemetry.io/collector v0.64.2-0.20221110222631-20e3aac00413 h1:pTl1k/nzEQ07s7VuK/+BXifRvcJ6/r76eI/QRkS41CE= +go.opentelemetry.io/collector v0.64.2-0.20221110222631-20e3aac00413/go.mod h1:RxdEKzwxTEhBAgzC4wzyJEwSFgjWU73CHnLjKUKQDyo= +go.opentelemetry.io/collector/pdata v0.64.2-0.20221110222631-20e3aac00413 h1:Ql3wWb5euyeB8/N6FGVZR2paZCi5Hy9uQTbC1Zg++h0= +go.opentelemetry.io/collector/pdata v0.64.2-0.20221110222631-20e3aac00413/go.mod h1:IzvXUGQml2mrnvdb8zIlEW3qQs9oFLdD2hLwJdZ+pek= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.36.4 h1:aUEBEdCa6iamGzg6fuYxDA8ThxvOG240mAvWDU+XLio= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.36.4/go.mod h1:l2MdsbKTocpPS5nQZscqTR9jd8u96VYZdcpF8Sye7mA= go.opentelemetry.io/otel v1.11.1 h1:4WLLAmcfkmDk2ukNXJyq3/kiz/3UzCaYq6PskJsaou4= diff --git a/exporter/logicmonitorexporter/logs_exporter.go b/exporter/logicmonitorexporter/logs_exporter.go index cf4ffcf06267..1a9949b99ea1 100644 --- a/exporter/logicmonitorexporter/logs_exporter.go +++ b/exporter/logicmonitorexporter/logs_exporter.go @@ -19,7 +19,7 @@ import ( "fmt" "github.com/logicmonitor/lm-data-sdk-go/api/logs" - "go.opentelemetry.io/collector/config" + "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/pdata/pcommon" "go.opentelemetry.io/collector/pdata/plog" "go.uber.org/zap" @@ -37,7 +37,7 @@ const ( ) // Create new logs exporter -func newLogsExporter(cfg config.Exporter, logger *zap.Logger) (*logExporter, error) { +func newLogsExporter(cfg component.ExporterConfig, logger *zap.Logger) (*logExporter, error) { oCfg := cfg.(*Config) isBatchEnabled := oCfg.LogBatchingEnabled diff --git a/exporter/logicmonitorexporter/logs_exporter_test.go b/exporter/logicmonitorexporter/logs_exporter_test.go index 97cea6609da0..4fbbd6f5134b 100644 --- a/exporter/logicmonitorexporter/logs_exporter_test.go +++ b/exporter/logicmonitorexporter/logs_exporter_test.go @@ -24,6 +24,7 @@ import ( "time" "github.com/logicmonitor/lm-data-sdk-go/api/logs" + "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/config" "go.opentelemetry.io/collector/pdata/pcommon" "go.opentelemetry.io/collector/pdata/plog" @@ -45,7 +46,7 @@ func Test_NewLogsExporter(t *testing.T) { "NewLogExporter: success", args{ config: &Config{ - ExporterSettings: config.NewExporterSettings(config.NewComponentID("logicmonitor")), + ExporterSettings: config.NewExporterSettings(component.NewID("logicmonitor")), URL: "https://test.logicmonitor.com/rest", APIToken: map[string]string{"access_id": "testid", "access_key": "testkey"}, LogBatchingEnabled: true, @@ -59,7 +60,7 @@ func Test_NewLogsExporter(t *testing.T) { "NewLogExporter: fail", args{ config: &Config{ - ExporterSettings: config.NewExporterSettings(config.NewComponentID("logicmonitor")), + ExporterSettings: config.NewExporterSettings(component.NewID("logicmonitor")), URL: "https://test.logicmonitor.com/rest", APIToken: map[string]string{"access_id": "testid", "access_key": "testkey"}, LogBatchingEnabled: true, diff --git a/exporter/logicmonitorexporter/traces_exporter_test.go b/exporter/logicmonitorexporter/traces_exporter_test.go index 0547596cf366..d556d013fcdc 100644 --- a/exporter/logicmonitorexporter/traces_exporter_test.go +++ b/exporter/logicmonitorexporter/traces_exporter_test.go @@ -74,7 +74,7 @@ func Test_newTraceExporter(t *testing.T) { "newTracesExporter: success", args{ config: &Config{ - ExporterSettings: config.NewExporterSettings(config.NewComponentID("logicmonitor")), + ExporterSettings: config.NewExporterSettings(component.NewID("logicmonitor")), APIToken: map[string]string{"access_id": "testid", "access_key": "testkey"}, }, logger: zap.NewNop(), @@ -112,7 +112,7 @@ func Test_newTraceExporter_InvalidURL(t *testing.T) { "newTracesExporter: success", args{ config: &Config{ - ExporterSettings: config.NewExporterSettings(config.NewComponentID("logicmonitor")), + ExporterSettings: config.NewExporterSettings(component.NewID("logicmonitor")), APIToken: map[string]string{"access_id": "testid", "access_key": "testkey"}, }, logger: zap.NewNop(), From e82e207c48d9e7d4848f5e3136e620b3c1743077 Mon Sep 17 00:00:00 2001 From: Khyati Gandhi Date: Tue, 15 Nov 2022 16:04:19 +0530 Subject: [PATCH 9/9] fix usage of deprecated types --- internal/components/exporters_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/components/exporters_test.go b/internal/components/exporters_test.go index 7a65de09670f..a6a745b2c483 100644 --- a/internal/components/exporters_test.go +++ b/internal/components/exporters_test.go @@ -385,7 +385,7 @@ func TestDefaultExporters(t *testing.T) { }, { exporter: "logicmonitor", - getConfigFn: func() config.Exporter { + getConfigFn: func() component.ExporterConfig { cfg := expFactories["logicmonitor"].CreateDefaultConfig().(*logicmonitorexporter.Config) return cfg },