diff --git a/cmd/otelcontribcol/builder-config.yaml b/cmd/otelcontribcol/builder-config.yaml
index b5421d1d3f9d..a8fbd102a651 100644
--- a/cmd/otelcontribcol/builder-config.yaml
+++ b/cmd/otelcontribcol/builder-config.yaml
@@ -166,6 +166,7 @@ receivers:
- gomod: github.com/open-telemetry/opentelemetry-collector-contrib/receiver/hostmetricsreceiver v0.108.0
- gomod: github.com/open-telemetry/opentelemetry-collector-contrib/receiver/httpcheckreceiver v0.108.0
- gomod: github.com/open-telemetry/opentelemetry-collector-contrib/receiver/huaweicloudcesreceiver v0.108.0
+ - gomod: github.com/open-telemetry/opentelemetry-collector-contrib/receiver/huaweicloudlogsreceiver v0.108.0
- gomod: github.com/open-telemetry/opentelemetry-collector-contrib/receiver/influxdbreceiver v0.108.0
- gomod: github.com/open-telemetry/opentelemetry-collector-contrib/receiver/iisreceiver v0.108.0
- gomod: github.com/open-telemetry/opentelemetry-collector-contrib/receiver/jaegerreceiver v0.108.0
@@ -260,6 +261,7 @@ replaces:
- github.com/open-telemetry/opentelemetry-collector-contrib/receiver/haproxyreceiver => ../../receiver/haproxyreceiver
- github.com/open-telemetry/opentelemetry-collector-contrib/receiver/httpcheckreceiver => ../../receiver/httpcheckreceiver
- github.com/open-telemetry/opentelemetry-collector-contrib/receiver/huaweicloudcesreceiver => ../../receiver/huaweicloudcesreceiver
+ - github.com/open-telemetry/opentelemetry-collector-contrib/receiver/huaweicloudlogsreceiver => ../../receiver/huaweicloudlogsreceiver
- github.com/open-telemetry/opentelemetry-collector-contrib/extension/observer/dockerobserver => ../../extension/observer/dockerobserver
- github.com/open-telemetry/opentelemetry-collector-contrib/extension/observer/k8sobserver => ../../extension/observer/k8sobserver
- github.com/open-telemetry/opentelemetry-collector-contrib/exporter/sentryexporter => ../../exporter/sentryexporter
@@ -502,4 +504,6 @@ replaces:
- github.com/open-telemetry/opentelemetry-collector-contrib/exporter/rabbitmqexporter => ../../exporter/rabbitmqexporter
- github.com/open-telemetry/opentelemetry-collector-contrib/receiver/githubreceiver => ../../receiver/githubreceiver
- github.com/open-telemetry/opentelemetry-collector-contrib/internal/grpcutil => ../../internal/grpcutil
+ - github.com/open-telemetry/opentelemetry-collector-contrib/internal/huawei => ../../internal/huawei
+
diff --git a/cmd/otelcontribcol/components.go b/cmd/otelcontribcol/components.go
index 664563e2c2e2..97724ff1c8dd 100644
--- a/cmd/otelcontribcol/components.go
+++ b/cmd/otelcontribcol/components.go
@@ -165,6 +165,7 @@ import (
hostmetricsreceiver "github.com/open-telemetry/opentelemetry-collector-contrib/receiver/hostmetricsreceiver"
httpcheckreceiver "github.com/open-telemetry/opentelemetry-collector-contrib/receiver/httpcheckreceiver"
huaweicloudcesreceiver "github.com/open-telemetry/opentelemetry-collector-contrib/receiver/huaweicloudcesreceiver"
+ huaweicloudlogsreceiver "github.com/open-telemetry/opentelemetry-collector-contrib/receiver/huaweicloudlogsreceiver"
iisreceiver "github.com/open-telemetry/opentelemetry-collector-contrib/receiver/iisreceiver"
influxdbreceiver "github.com/open-telemetry/opentelemetry-collector-contrib/receiver/influxdbreceiver"
jaegerreceiver "github.com/open-telemetry/opentelemetry-collector-contrib/receiver/jaegerreceiver"
@@ -339,6 +340,7 @@ func components() (otelcol.Factories, error) {
hostmetricsreceiver.NewFactory(),
httpcheckreceiver.NewFactory(),
huaweicloudcesreceiver.NewFactory(),
+ huaweicloudlogsreceiver.NewFactory(),
influxdbreceiver.NewFactory(),
iisreceiver.NewFactory(),
jaegerreceiver.NewFactory(),
@@ -436,6 +438,7 @@ func components() (otelcol.Factories, error) {
factories.ReceiverModules[hostmetricsreceiver.NewFactory().Type()] = "github.com/open-telemetry/opentelemetry-collector-contrib/receiver/hostmetricsreceiver v0.108.0"
factories.ReceiverModules[httpcheckreceiver.NewFactory().Type()] = "github.com/open-telemetry/opentelemetry-collector-contrib/receiver/httpcheckreceiver v0.108.0"
factories.ReceiverModules[huaweicloudcesreceiver.NewFactory().Type()] = "github.com/open-telemetry/opentelemetry-collector-contrib/receiver/huaweicloudcesreceiver v0.108.0"
+ factories.ReceiverModules[huaweicloudlogsreceiver.NewFactory().Type()] = "github.com/open-telemetry/opentelemetry-collector-contrib/receiver/huaweicloudlogsreceiver v0.108.0"
factories.ReceiverModules[influxdbreceiver.NewFactory().Type()] = "github.com/open-telemetry/opentelemetry-collector-contrib/receiver/influxdbreceiver v0.108.0"
factories.ReceiverModules[iisreceiver.NewFactory().Type()] = "github.com/open-telemetry/opentelemetry-collector-contrib/receiver/iisreceiver v0.108.0"
factories.ReceiverModules[jaegerreceiver.NewFactory().Type()] = "github.com/open-telemetry/opentelemetry-collector-contrib/receiver/jaegerreceiver v0.108.0"
diff --git a/cmd/otelcontribcol/go.mod b/cmd/otelcontribcol/go.mod
index 0dc083d4c951..eb273291f012 100644
--- a/cmd/otelcontribcol/go.mod
+++ b/cmd/otelcontribcol/go.mod
@@ -2,7 +2,7 @@
module github.com/open-telemetry/opentelemetry-collector-contrib/cmd/otelcontribcol
-go 1.22.0
+go 1.22.3
toolchain go1.22.7
@@ -155,6 +155,7 @@ require (
github.com/open-telemetry/opentelemetry-collector-contrib/receiver/hostmetricsreceiver v0.108.0
github.com/open-telemetry/opentelemetry-collector-contrib/receiver/httpcheckreceiver v0.108.0
github.com/open-telemetry/opentelemetry-collector-contrib/receiver/huaweicloudcesreceiver v0.108.0
+ github.com/open-telemetry/opentelemetry-collector-contrib/receiver/huaweicloudlogsreceiver v0.108.0
github.com/open-telemetry/opentelemetry-collector-contrib/receiver/iisreceiver v0.108.0
github.com/open-telemetry/opentelemetry-collector-contrib/receiver/influxdbreceiver v0.108.0
github.com/open-telemetry/opentelemetry-collector-contrib/receiver/jaegerreceiver v0.108.0
@@ -645,6 +646,7 @@ require (
github.com/open-telemetry/opentelemetry-collector-contrib/internal/exp/metrics v0.108.0 // indirect
github.com/open-telemetry/opentelemetry-collector-contrib/internal/filter v0.108.0 // indirect
github.com/open-telemetry/opentelemetry-collector-contrib/internal/grpcutil v0.108.0 // indirect
+ github.com/open-telemetry/opentelemetry-collector-contrib/internal/huawei v0.108.0 // indirect
github.com/open-telemetry/opentelemetry-collector-contrib/internal/k8sconfig v0.108.0 // indirect
github.com/open-telemetry/opentelemetry-collector-contrib/internal/kafka v0.108.0 // indirect
github.com/open-telemetry/opentelemetry-collector-contrib/internal/kubelet v0.108.0 // indirect
@@ -810,7 +812,7 @@ require (
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.54.0 // indirect
go.opentelemetry.io/contrib/propagators/b3 v1.29.0 // indirect
go.opentelemetry.io/contrib/zpages v0.54.0 // indirect
- go.opentelemetry.io/otel v1.29.0 // indirect
+ go.opentelemetry.io/otel v1.30.0 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.5.0 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.29.0 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.29.0 // indirect
@@ -822,11 +824,11 @@ require (
go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.29.0 // indirect
go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.29.0 // indirect
go.opentelemetry.io/otel/log v0.5.0 // indirect
- go.opentelemetry.io/otel/metric v1.29.0 // indirect
+ go.opentelemetry.io/otel/metric v1.30.0 // indirect
go.opentelemetry.io/otel/sdk v1.29.0 // indirect
go.opentelemetry.io/otel/sdk/log v0.5.0 // indirect
go.opentelemetry.io/otel/sdk/metric v1.29.0 // indirect
- go.opentelemetry.io/otel/trace v1.29.0 // indirect
+ go.opentelemetry.io/otel/trace v1.30.0 // indirect
go.opentelemetry.io/proto/otlp v1.3.1 // indirect
go.uber.org/atomic v1.11.0 // indirect
go.uber.org/dig v1.17.1 // indirect
@@ -900,6 +902,8 @@ replace github.com/open-telemetry/opentelemetry-collector-contrib/receiver/httpc
replace github.com/open-telemetry/opentelemetry-collector-contrib/receiver/huaweicloudcesreceiver => ../../receiver/huaweicloudcesreceiver
+replace github.com/open-telemetry/opentelemetry-collector-contrib/receiver/huaweicloudlogsreceiver => ../../receiver/huaweicloudlogsreceiver
+
replace github.com/open-telemetry/opentelemetry-collector-contrib/extension/observer/dockerobserver => ../../extension/observer/dockerobserver
replace github.com/open-telemetry/opentelemetry-collector-contrib/extension/observer/k8sobserver => ../../extension/observer/k8sobserver
@@ -1381,3 +1385,5 @@ replace github.com/open-telemetry/opentelemetry-collector-contrib/exporter/rabbi
replace github.com/open-telemetry/opentelemetry-collector-contrib/receiver/githubreceiver => ../../receiver/githubreceiver
replace github.com/open-telemetry/opentelemetry-collector-contrib/internal/grpcutil => ../../internal/grpcutil
+
+replace github.com/open-telemetry/opentelemetry-collector-contrib/internal/huawei => ../../internal/huawei
diff --git a/cmd/otelcontribcol/go.sum b/cmd/otelcontribcol/go.sum
index 950b0ba8c5cc..0d482f22e56f 100644
--- a/cmd/otelcontribcol/go.sum
+++ b/cmd/otelcontribcol/go.sum
@@ -2460,8 +2460,8 @@ go.opentelemetry.io/contrib/propagators/b3 v1.29.0 h1:hNjyoRsAACnhoOLWupItUjABze
go.opentelemetry.io/contrib/propagators/b3 v1.29.0/go.mod h1:E76MTitU1Niwo5NSN+mVxkyLu4h4h7Dp/yh38F2WuIU=
go.opentelemetry.io/contrib/zpages v0.54.0 h1:tSfm/LEK5E46sd5qx/Y9o4iQ65ipLubV0Una7veXFlA=
go.opentelemetry.io/contrib/zpages v0.54.0/go.mod h1:sbe4/RH3CFKkdM5zuGwfziKjvkqUOK9hSgLFckiVZUI=
-go.opentelemetry.io/otel v1.29.0 h1:PdomN/Al4q/lN6iBJEN3AwPvUiHPMlt93c8bqTG5Llw=
-go.opentelemetry.io/otel v1.29.0/go.mod h1:N/WtXPs1CNCUEx+Agz5uouwCba+i+bJGFicT8SR4NP8=
+go.opentelemetry.io/otel v1.30.0 h1:F2t8sK4qf1fAmY9ua4ohFS/K+FUuOPemHUIXHtktrts=
+go.opentelemetry.io/otel v1.30.0/go.mod h1:tFw4Br9b7fOS+uEao81PJjVMjW/5fvNCbpsDIXqP0pc=
go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.5.0 h1:4d++HQ+Ihdl+53zSjtsCUFDmNMju2FC9qFkUlTxPLqo=
go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.5.0/go.mod h1:mQX5dTO3Mh5ZF7bPKDkt5c/7C41u/SiDr9XgTpzXXn8=
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.29.0 h1:k6fQVDQexDE+3jG2SfCQjnHS7OamcP73YMoxEVq5B6k=
@@ -2484,16 +2484,16 @@ go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.29.0 h1:X3ZjNp36/WlkSYx
go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.29.0/go.mod h1:2uL/xnOXh0CHOBFCWXz5u1A4GXLiW+0IQIzVbeOEQ0U=
go.opentelemetry.io/otel/log v0.5.0 h1:x1Pr6Y3gnXgl1iFBwtGy1W/mnzENoK0w0ZoaeOI3i30=
go.opentelemetry.io/otel/log v0.5.0/go.mod h1:NU/ozXeGuOR5/mjCRXYbTC00NFJ3NYuraV/7O78F0rE=
-go.opentelemetry.io/otel/metric v1.29.0 h1:vPf/HFWTNkPu1aYeIsc98l4ktOQaL6LeSoeV2g+8YLc=
-go.opentelemetry.io/otel/metric v1.29.0/go.mod h1:auu/QWieFVWx+DmQOUMgj0F8LHWdgalxXqvp7BII/W8=
+go.opentelemetry.io/otel/metric v1.30.0 h1:4xNulvn9gjzo4hjg+wzIKG7iNFEaBMX00Qd4QIZs7+w=
+go.opentelemetry.io/otel/metric v1.30.0/go.mod h1:aXTfST94tswhWEb+5QjlSqG+cZlmyXy/u8jFpor3WqQ=
go.opentelemetry.io/otel/sdk v1.29.0 h1:vkqKjk7gwhS8VaWb0POZKmIEDimRCMsopNYnriHyryo=
go.opentelemetry.io/otel/sdk v1.29.0/go.mod h1:pM8Dx5WKnvxLCb+8lG1PRNIDxu9g9b9g59Qr7hfAAok=
go.opentelemetry.io/otel/sdk/log v0.5.0 h1:A+9lSjlZGxkQOr7QSBJcuyyYBw79CufQ69saiJLey7o=
go.opentelemetry.io/otel/sdk/log v0.5.0/go.mod h1:zjxIW7sw1IHolZL2KlSAtrUi8JHttoeiQy43Yl3WuVQ=
go.opentelemetry.io/otel/sdk/metric v1.29.0 h1:K2CfmJohnRgvZ9UAj2/FhIf/okdWcNdBwe1m8xFXiSY=
go.opentelemetry.io/otel/sdk/metric v1.29.0/go.mod h1:6zZLdCl2fkauYoZIOn/soQIDSWFmNSRcICarHfuhNJQ=
-go.opentelemetry.io/otel/trace v1.29.0 h1:J/8ZNK4XgR7a21DZUAsbF8pZ5Jcw1VhACmnYt39JTi4=
-go.opentelemetry.io/otel/trace v1.29.0/go.mod h1:eHl3w0sp3paPkYstJOmAimxhiFXPg+MMTlEh3nsQgWQ=
+go.opentelemetry.io/otel/trace v1.30.0 h1:7UBkkYzeg3C7kQX8VAidWh2biiQbtAKjyIML8dQ9wmc=
+go.opentelemetry.io/otel/trace v1.30.0/go.mod h1:5EyKqTzzmyqB9bwtCCq6pDLktPK6fmGf/Dph+8VI02o=
go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=
go.opentelemetry.io/proto/otlp v0.15.0/go.mod h1:H7XAot3MsfNsj7EXtrA2q5xSNQ10UqI405h3+duxN4U=
go.opentelemetry.io/proto/otlp v0.19.0/go.mod h1:H7XAot3MsfNsj7EXtrA2q5xSNQ10UqI405h3+duxN4U=
diff --git a/internal/huawei/Makefile b/internal/huawei/Makefile
new file mode 100644
index 000000000000..ded7a36092dc
--- /dev/null
+++ b/internal/huawei/Makefile
@@ -0,0 +1 @@
+include ../../Makefile.Common
diff --git a/receiver/huaweicloudcesreceiver/internal/backoff.go b/internal/huawei/backoff.go
similarity index 77%
rename from receiver/huaweicloudcesreceiver/internal/backoff.go
rename to internal/huawei/backoff.go
index 7ad525bfa62c..39f5fc6e81b3 100644
--- a/receiver/huaweicloudcesreceiver/internal/backoff.go
+++ b/internal/huawei/backoff.go
@@ -1,7 +1,7 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0
-package internal // import "github.com/open-telemetry/opentelemetry-collector-contrib/receiver/huaweicloudcesreceiver/internal"
+package huawei // import "github.com/open-telemetry/opentelemetry-collector-contrib/internal/huawei"
import (
"context"
@@ -9,9 +9,22 @@ import (
"time"
"github.com/cenkalti/backoff/v4"
+ "go.opentelemetry.io/collector/config/configretry"
"go.uber.org/zap"
)
+func NewExponentialBackOff(backOffConfig *configretry.BackOffConfig) *backoff.ExponentialBackOff {
+ return &backoff.ExponentialBackOff{
+ InitialInterval: backOffConfig.InitialInterval,
+ RandomizationFactor: backOffConfig.RandomizationFactor,
+ Multiplier: backOffConfig.Multiplier,
+ MaxInterval: backOffConfig.MaxInterval,
+ MaxElapsedTime: backOffConfig.MaxElapsedTime,
+ Stop: backoff.Stop,
+ Clock: backoff.SystemClock,
+ }
+}
+
// Generic function to make an API call with exponential backoff and context cancellation handling.
func MakeAPICallWithRetry[T any](
ctx context.Context,
diff --git a/receiver/huaweicloudcesreceiver/internal/backoff_test.go b/internal/huawei/backoff_test.go
similarity index 99%
rename from receiver/huaweicloudcesreceiver/internal/backoff_test.go
rename to internal/huawei/backoff_test.go
index 402a1f23ace8..f8448223e046 100644
--- a/receiver/huaweicloudcesreceiver/internal/backoff_test.go
+++ b/internal/huawei/backoff_test.go
@@ -1,7 +1,7 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0
-package internal
+package huawei
import (
"context"
diff --git a/internal/huawei/client_config.go b/internal/huawei/client_config.go
new file mode 100644
index 000000000000..b24d079e63ca
--- /dev/null
+++ b/internal/huawei/client_config.go
@@ -0,0 +1,66 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+package huawei // import "github.com/open-telemetry/opentelemetry-collector-contrib/internal/huawei"
+
+import (
+ "errors"
+ "net/url"
+ "strconv"
+
+ "github.com/huaweicloud/huaweicloud-sdk-go-v3/core/config"
+ "go.opentelemetry.io/collector/config/configopaque"
+)
+
+var (
+ // Predefined error responses for configuration validation failures
+ ErrMissingProjectID = errors.New(`"project_id" is not specified in config`)
+ ErrMissingRegionID = errors.New(`"region_id" is not specified in config`)
+
+ ErrInvalidProxy = errors.New(`"proxy_address" must be specified if "proxy_user" or "proxy_password" is set"`)
+)
+
+type HuaweiSessionConfig struct {
+ AccessKey configopaque.String `mapstructure:"access_key"`
+
+ SecretKey configopaque.String `mapstructure:"secret_key"`
+ // Number of seconds before timing out a request.
+ NoVerifySSL bool `mapstructure:"no_verify_ssl"`
+ // Upload segments to AWS X-Ray through a proxy.
+ ProxyAddress string `mapstructure:"proxy_address"`
+ ProxyUser string `mapstructure:"proxy_user"`
+ ProxyPassword string `mapstructure:"proxy_password"`
+}
+
+func CreateHTTPConfig(cfg HuaweiSessionConfig) (*config.HttpConfig, error) {
+ if cfg.ProxyAddress == "" {
+ return config.DefaultHttpConfig().WithIgnoreSSLVerification(cfg.NoVerifySSL), nil
+ }
+ proxy, err := configureHTTPProxy(cfg)
+ if err != nil {
+ return nil, err
+ }
+ return config.DefaultHttpConfig().WithProxy(proxy), nil
+}
+
+func configureHTTPProxy(cfg HuaweiSessionConfig) (*config.Proxy, error) {
+ proxyURL, err := url.Parse(cfg.ProxyAddress)
+ if err != nil {
+ return nil, err
+ }
+
+ proxy := config.NewProxy().
+ WithSchema(proxyURL.Scheme).
+ WithHost(proxyURL.Hostname())
+ if len(proxyURL.Port()) > 0 {
+ if i, err := strconv.Atoi(proxyURL.Port()); err == nil {
+ proxy = proxy.WithPort(i)
+ }
+ }
+
+ // Configure the username and password if the proxy requires authentication
+ if len(cfg.ProxyUser) > 0 {
+ proxy = proxy.WithUsername(cfg.ProxyUser).WithPassword(cfg.ProxyPassword)
+ }
+ return proxy, nil
+}
diff --git a/internal/huawei/client_config_test.go b/internal/huawei/client_config_test.go
new file mode 100644
index 000000000000..b95f3a11d537
--- /dev/null
+++ b/internal/huawei/client_config_test.go
@@ -0,0 +1,33 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+package huawei
+
+import (
+ "testing"
+
+ "github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/require"
+)
+
+func TestCreateHTTPConfigNoVerifySSL(t *testing.T) {
+ cfg, err := CreateHTTPConfig(HuaweiSessionConfig{NoVerifySSL: true})
+ require.NoError(t, err)
+ assert.True(t, cfg.IgnoreSSLVerification)
+}
+
+func TestCreateHTTPConfigWithProxy(t *testing.T) {
+ cfg, err := CreateHTTPConfig(HuaweiSessionConfig{
+ ProxyAddress: "https://127.0.0.1:8888",
+ ProxyUser: "admin",
+ ProxyPassword: "pass",
+ AccessKey: "123",
+ SecretKey: "secret",
+ })
+ require.NoError(t, err)
+ assert.Equal(t, "https", cfg.HttpProxy.Schema)
+ assert.Equal(t, "127.0.0.1", cfg.HttpProxy.Host)
+ assert.Equal(t, 8888, cfg.HttpProxy.Port)
+ assert.False(t, cfg.IgnoreSSLVerification)
+
+}
diff --git a/internal/huawei/go.mod b/internal/huawei/go.mod
new file mode 100644
index 000000000000..36b43a65c5d8
--- /dev/null
+++ b/internal/huawei/go.mod
@@ -0,0 +1,19 @@
+module github.com/open-telemetry/opentelemetry-collector-contrib/internal/huawei
+
+go 1.22.3
+
+require (
+ github.com/cenkalti/backoff/v4 v4.3.0
+ github.com/huaweicloud/huaweicloud-sdk-go-v3 v0.1.113
+ github.com/stretchr/testify v1.9.0
+ go.opentelemetry.io/collector/config/configopaque v1.15.0
+ go.opentelemetry.io/collector/config/configretry v1.15.0
+ go.uber.org/zap v1.27.0
+)
+
+require (
+ github.com/davecgh/go-spew v1.1.1 // indirect
+ github.com/pmezard/go-difflib v1.0.0 // indirect
+ go.uber.org/multierr v1.10.0 // indirect
+ gopkg.in/yaml.v3 v3.0.1 // indirect
+)
diff --git a/internal/huawei/go.sum b/internal/huawei/go.sum
new file mode 100644
index 000000000000..761089fc8bde
--- /dev/null
+++ b/internal/huawei/go.sum
@@ -0,0 +1,166 @@
+cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
+github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
+github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8=
+github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
+github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
+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/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
+github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
+github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
+github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
+github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
+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.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.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
+github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
+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.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
+github.com/huaweicloud/huaweicloud-sdk-go-v3 v0.1.113 h1:odui9Ua0u1hPfpkutN/tGvtt0ms55I+gQqIdU8K1rlo=
+github.com/huaweicloud/huaweicloud-sdk-go-v3 v0.1.113/go.mod h1:JWz2ujO9X3oU5wb6kXp+DpR2UuDj2SldDbX8T0FSuhI=
+github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
+github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk=
+github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
+github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
+github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
+github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
+github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
+github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
+github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc=
+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/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
+github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ=
+github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog=
+github.com/stretchr/objx v0.1.0/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.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
+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.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
+github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
+github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
+github.com/tjfoc/gmsm v1.4.1/go.mod h1:j4INPkHWMrhJb38G+J6W4Tw0AbuN8Thu3PbdVYhVcTE=
+github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI=
+github.com/xdg-go/scram v1.1.2/go.mod h1:RT/sEzTbU5y00aCK8UOx6R7YryM0iF1N2MOmC3kKLN4=
+github.com/xdg-go/stringprep v1.0.4/go.mod h1:mPGuuIYwz7CmR2bT9j4GbQqutWS1zV24gijq1dTyGkM=
+github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d/go.mod h1:rHwXgn7JulP+udvsHwJoVG1YGAP6VLg4y9I5dyZdqmA=
+github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
+go.mongodb.org/mongo-driver v1.12.0/go.mod h1:AZkxhPnFJUoH7kZlFkVKucV20K387miPfm7oimrSmK0=
+go.opentelemetry.io/collector/config/configopaque v1.15.0 h1:J1rmPR1WGro7BNCgni3o+VDoyB7ZqH2/SG1YK+6ujCw=
+go.opentelemetry.io/collector/config/configopaque v1.15.0/go.mod h1:6zlLIyOoRpJJ+0bEKrlZOZon3rOp5Jrz9fMdR4twOS4=
+go.opentelemetry.io/collector/config/configretry v1.15.0 h1:4ZUPrWWh4wiwdlGnss2lZDhvf1xkt8uwHEqmuqovMEs=
+go.opentelemetry.io/collector/config/configretry v1.15.0/go.mod h1:KvQF5cfphq1rQm1dKR4eLDNQYw6iI2fY72NMZVa+0N0=
+go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
+go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
+go.uber.org/multierr v1.10.0 h1:S0h4aNzvfcFsC3dRF1jLoaov7oRaKqRGC/pUEJ2yvPQ=
+go.uber.org/multierr v1.10.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
+go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8=
+go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E=
+golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
+golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
+golang.org/x/crypto v0.0.0-20201012173705-84dcc777aaee/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
+golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
+golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
+golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
+golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
+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/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
+golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
+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-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20201010224723-4f7140c49acb/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-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
+golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
+golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
+golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
+golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
+golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
+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-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/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-20190412213103-97732733099d/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-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
+golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
+golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
+golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
+golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
+golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
+golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk=
+golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY=
+golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
+golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
+golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
+golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
+golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
+golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
+golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
+golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
+golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
+golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
+golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
+golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
+golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
+golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
+golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/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-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
+google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
+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.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
+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.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
+gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
+gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
+gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
+gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/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=
diff --git a/receiver/huaweicloudcesreceiver/config.go b/receiver/huaweicloudcesreceiver/config.go
index 076ec7a9c024..5d9bf5c8064b 100644
--- a/receiver/huaweicloudcesreceiver/config.go
+++ b/receiver/huaweicloudcesreceiver/config.go
@@ -9,9 +9,9 @@ import (
"slices"
"github.com/huaweicloud/huaweicloud-sdk-go-v3/services/ces/v1/model"
+ "github.com/open-telemetry/opentelemetry-collector-contrib/internal/huawei"
"go.opentelemetry.io/collector/component"
"go.opentelemetry.io/collector/config/confighttp"
- "go.opentelemetry.io/collector/config/configopaque"
"go.opentelemetry.io/collector/config/configretry"
"go.opentelemetry.io/collector/receiver/scraperhelper"
"go.uber.org/multierr"
@@ -19,8 +19,6 @@ import (
var (
// Predefined error responses for configuration validation failures
- errMissingRegionID = errors.New(`"region_id" is not specified in config`)
- errMissingProjectID = errors.New(`"project_id" is not specified in config`)
errInvalidCollectionInterval = errors.New(`invalid period; must be less than "collection_interval"`)
errInvalidProxy = errors.New(`"proxy_address" must be specified if "proxy_user" or "proxy_password" is set"`)
)
@@ -41,7 +39,7 @@ type Config struct {
// If Indices is empty, no indices will be scraped.
Indices []string `mapstructure:"indices"`
// Set of attributes used to configure huawei's CES SDK connection
- HuaweiSessionConfig `mapstructure:",squash"`
+ huawei.HuaweiSessionConfig `mapstructure:",squash"`
// ProjectID is a string to reference project where metrics should be associated with.
// If ProjectID is not filled in, the SDK will automatically call the IAM service to query the project id corresponding to the region.
@@ -67,18 +65,6 @@ type Config struct {
BackOffConfig configretry.BackOffConfig `mapstructure:"retry_on_failure"`
}
-type HuaweiSessionConfig struct {
- AccessKey configopaque.String `mapstructure:"access_key"`
-
- SecretKey configopaque.String `mapstructure:"secret_key"`
- // Number of seconds before timing out a request.
- NoVerifySSL bool `mapstructure:"no_verify_ssl"`
- // Upload segments to AWS X-Ray through a proxy.
- ProxyAddress string `mapstructure:"proxy_address"`
- ProxyUser string `mapstructure:"proxy_user"`
- ProxyPassword string `mapstructure:"proxy_password"`
-}
-
var _ component.Config = (*Config)(nil)
// These valid periods are defined by CES API constraints: https://support.huaweicloud.com/intl/en-us/api-ces/ces_03_0034.html#section3
@@ -97,11 +83,11 @@ var validFilters = map[string]model.ShowMetricDataRequestFilter{
func (config *Config) Validate() error {
var err error
if config.RegionID == "" {
- err = multierr.Append(err, errMissingRegionID)
+ err = multierr.Append(err, huawei.ErrMissingRegionID)
}
if config.ProjectID == "" {
- err = multierr.Append(err, errMissingProjectID)
+ err = multierr.Append(err, huawei.ErrMissingProjectID)
}
if index := slices.Index(validPeriods, config.Period); index == -1 {
err = multierr.Append(err, fmt.Errorf("invalid period: got %d; must be one of %v", config.Period, validPeriods))
diff --git a/receiver/huaweicloudcesreceiver/config_test.go b/receiver/huaweicloudcesreceiver/config_test.go
index 7edf5ed2a7c2..4dae651a757e 100644
--- a/receiver/huaweicloudcesreceiver/config_test.go
+++ b/receiver/huaweicloudcesreceiver/config_test.go
@@ -7,6 +7,7 @@ import (
"testing"
"time"
+ "github.com/open-telemetry/opentelemetry-collector-contrib/internal/huawei"
"github.com/stretchr/testify/assert"
"go.opentelemetry.io/collector/receiver/scraperhelper"
)
@@ -63,7 +64,7 @@ func TestConfigValidate(t *testing.T) {
Period: 300,
Filter: "min",
},
- expectedError: errMissingRegionID.Error(),
+ expectedError: huawei.ErrMissingRegionID.Error(),
},
{
name: "Missing project id",
@@ -75,12 +76,12 @@ func TestConfigValidate(t *testing.T) {
Period: 300,
Filter: "min",
},
- expectedError: errMissingProjectID.Error(),
+ expectedError: huawei.ErrMissingProjectID.Error(),
},
{
name: "Proxy user without proxy address",
config: Config{
- HuaweiSessionConfig: HuaweiSessionConfig{
+ HuaweiSessionConfig: huawei.HuaweiSessionConfig{
ProxyUser: "user",
},
ControllerConfig: scraperhelper.ControllerConfig{
@@ -96,7 +97,7 @@ func TestConfigValidate(t *testing.T) {
{
name: "Proxy password without proxy address",
config: Config{
- HuaweiSessionConfig: HuaweiSessionConfig{
+ HuaweiSessionConfig: huawei.HuaweiSessionConfig{
ProxyPassword: "password",
},
ControllerConfig: scraperhelper.ControllerConfig{
@@ -112,7 +113,7 @@ func TestConfigValidate(t *testing.T) {
{
name: "Proxy address with proxy user and password",
config: Config{
- HuaweiSessionConfig: HuaweiSessionConfig{
+ HuaweiSessionConfig: huawei.HuaweiSessionConfig{
ProxyAddress: "http://proxy.example.com",
ProxyUser: "user",
ProxyPassword: "password",
diff --git a/receiver/huaweicloudcesreceiver/factory.go b/receiver/huaweicloudcesreceiver/factory.go
index 5f5426680e5d..7ebe0258122f 100644
--- a/receiver/huaweicloudcesreceiver/factory.go
+++ b/receiver/huaweicloudcesreceiver/factory.go
@@ -13,6 +13,7 @@ import (
"go.opentelemetry.io/collector/consumer"
"go.opentelemetry.io/collector/receiver"
+ "github.com/open-telemetry/opentelemetry-collector-contrib/internal/huawei"
"github.com/open-telemetry/opentelemetry-collector-contrib/receiver/huaweicloudcesreceiver/internal/metadata"
)
@@ -33,7 +34,7 @@ func createDefaultConfig() component.Config {
RandomizationFactor: backoff.DefaultRandomizationFactor,
Multiplier: backoff.DefaultMultiplier,
},
- HuaweiSessionConfig: HuaweiSessionConfig{
+ HuaweiSessionConfig: huawei.HuaweiSessionConfig{
NoVerifySSL: false,
},
}
diff --git a/receiver/huaweicloudcesreceiver/go.mod b/receiver/huaweicloudcesreceiver/go.mod
index c75867cf7c88..6308c2188f96 100644
--- a/receiver/huaweicloudcesreceiver/go.mod
+++ b/receiver/huaweicloudcesreceiver/go.mod
@@ -1,18 +1,16 @@
module github.com/open-telemetry/opentelemetry-collector-contrib/receiver/huaweicloudcesreceiver
-go 1.22.0
-
-toolchain go1.22.3
+go 1.22.3
require (
github.com/cenkalti/backoff/v4 v4.3.0
github.com/huaweicloud/huaweicloud-sdk-go-v3 v0.1.113
+ github.com/open-telemetry/opentelemetry-collector-contrib/internal/huawei v0.108.0
github.com/open-telemetry/opentelemetry-collector-contrib/pkg/golden v0.108.0
github.com/open-telemetry/opentelemetry-collector-contrib/pkg/pdatatest v0.107.0
github.com/stretchr/testify v1.9.0
go.opentelemetry.io/collector/component v0.109.0
go.opentelemetry.io/collector/config/confighttp v0.109.0
- go.opentelemetry.io/collector/config/configopaque v1.15.0
go.opentelemetry.io/collector/config/configretry v1.15.0
go.opentelemetry.io/collector/confmap v1.15.0
go.opentelemetry.io/collector/consumer v0.109.0
@@ -61,6 +59,7 @@ require (
go.opentelemetry.io/collector/client v1.15.0 // indirect
go.opentelemetry.io/collector/config/configauth v0.109.0 // indirect
go.opentelemetry.io/collector/config/configcompression v1.15.0 // indirect
+ go.opentelemetry.io/collector/config/configopaque v1.15.0 // indirect
go.opentelemetry.io/collector/config/configtelemetry v0.109.0 // indirect
go.opentelemetry.io/collector/config/configtls v1.15.0 // indirect
go.opentelemetry.io/collector/config/internal v0.109.0 // indirect
@@ -71,12 +70,12 @@ require (
go.opentelemetry.io/collector/pdata/pprofile v0.109.0 // indirect
go.opentelemetry.io/collector/receiver/receiverprofiles v0.109.0 // indirect
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.54.0 // indirect
- go.opentelemetry.io/otel v1.29.0 // indirect
+ go.opentelemetry.io/otel v1.30.0 // indirect
go.opentelemetry.io/otel/exporters/prometheus v0.51.0 // indirect
- go.opentelemetry.io/otel/metric v1.29.0 // indirect
+ go.opentelemetry.io/otel/metric v1.30.0 // indirect
go.opentelemetry.io/otel/sdk v1.29.0 // indirect
go.opentelemetry.io/otel/sdk/metric v1.29.0 // indirect
- go.opentelemetry.io/otel/trace v1.29.0 // indirect
+ go.opentelemetry.io/otel/trace v1.30.0 // indirect
golang.org/x/crypto v0.27.0 // indirect
golang.org/x/net v0.29.0 // indirect
golang.org/x/sys v0.25.0 // indirect
@@ -88,6 +87,8 @@ require (
gopkg.in/yaml.v3 v3.0.1 // indirect
)
+replace github.com/open-telemetry/opentelemetry-collector-contrib/internal/huawei => ./../../internal/huawei
+
replace github.com/open-telemetry/opentelemetry-collector-contrib/pkg/pdatautil => ../../pkg/pdatautil
replace github.com/open-telemetry/opentelemetry-collector-contrib/pkg/pdatatest => ../../pkg/pdatatest
diff --git a/receiver/huaweicloudcesreceiver/go.sum b/receiver/huaweicloudcesreceiver/go.sum
index cfc00296c454..ae4a2a11a1eb 100644
--- a/receiver/huaweicloudcesreceiver/go.sum
+++ b/receiver/huaweicloudcesreceiver/go.sum
@@ -173,18 +173,18 @@ go.opentelemetry.io/collector/receiver/receiverprofiles v0.109.0 h1:KKzdIixE/XJW
go.opentelemetry.io/collector/receiver/receiverprofiles v0.109.0/go.mod h1:FKU+RFkSLWWB3tUUB6vifapZdFp1FoqVYVQ22jpHc8w=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.54.0 h1:TT4fX+nBOA/+LUkobKGW1ydGcn+G3vRw9+g5HwCphpk=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.54.0/go.mod h1:L7UH0GbB0p47T4Rri3uHjbpCFYrVrwc1I25QhNPiGK8=
-go.opentelemetry.io/otel v1.29.0 h1:PdomN/Al4q/lN6iBJEN3AwPvUiHPMlt93c8bqTG5Llw=
-go.opentelemetry.io/otel v1.29.0/go.mod h1:N/WtXPs1CNCUEx+Agz5uouwCba+i+bJGFicT8SR4NP8=
+go.opentelemetry.io/otel v1.30.0 h1:F2t8sK4qf1fAmY9ua4ohFS/K+FUuOPemHUIXHtktrts=
+go.opentelemetry.io/otel v1.30.0/go.mod h1:tFw4Br9b7fOS+uEao81PJjVMjW/5fvNCbpsDIXqP0pc=
go.opentelemetry.io/otel/exporters/prometheus v0.51.0 h1:G7uexXb/K3T+T9fNLCCKncweEtNEBMTO+46hKX5EdKw=
go.opentelemetry.io/otel/exporters/prometheus v0.51.0/go.mod h1:v0mFe5Kk7woIh938mrZBJBmENYquyA0IICrlYm4Y0t4=
-go.opentelemetry.io/otel/metric v1.29.0 h1:vPf/HFWTNkPu1aYeIsc98l4ktOQaL6LeSoeV2g+8YLc=
-go.opentelemetry.io/otel/metric v1.29.0/go.mod h1:auu/QWieFVWx+DmQOUMgj0F8LHWdgalxXqvp7BII/W8=
+go.opentelemetry.io/otel/metric v1.30.0 h1:4xNulvn9gjzo4hjg+wzIKG7iNFEaBMX00Qd4QIZs7+w=
+go.opentelemetry.io/otel/metric v1.30.0/go.mod h1:aXTfST94tswhWEb+5QjlSqG+cZlmyXy/u8jFpor3WqQ=
go.opentelemetry.io/otel/sdk v1.29.0 h1:vkqKjk7gwhS8VaWb0POZKmIEDimRCMsopNYnriHyryo=
go.opentelemetry.io/otel/sdk v1.29.0/go.mod h1:pM8Dx5WKnvxLCb+8lG1PRNIDxu9g9b9g59Qr7hfAAok=
go.opentelemetry.io/otel/sdk/metric v1.29.0 h1:K2CfmJohnRgvZ9UAj2/FhIf/okdWcNdBwe1m8xFXiSY=
go.opentelemetry.io/otel/sdk/metric v1.29.0/go.mod h1:6zZLdCl2fkauYoZIOn/soQIDSWFmNSRcICarHfuhNJQ=
-go.opentelemetry.io/otel/trace v1.29.0 h1:J/8ZNK4XgR7a21DZUAsbF8pZ5Jcw1VhACmnYt39JTi4=
-go.opentelemetry.io/otel/trace v1.29.0/go.mod h1:eHl3w0sp3paPkYstJOmAimxhiFXPg+MMTlEh3nsQgWQ=
+go.opentelemetry.io/otel/trace v1.30.0 h1:7UBkkYzeg3C7kQX8VAidWh2biiQbtAKjyIML8dQ9wmc=
+go.opentelemetry.io/otel/trace v1.30.0/go.mod h1:5EyKqTzzmyqB9bwtCCq6pDLktPK6fmGf/Dph+8VI02o=
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
diff --git a/receiver/huaweicloudcesreceiver/receiver.go b/receiver/huaweicloudcesreceiver/receiver.go
index dc4ba5683d3f..be086dc66199 100644
--- a/receiver/huaweicloudcesreceiver/receiver.go
+++ b/receiver/huaweicloudcesreceiver/receiver.go
@@ -7,23 +7,19 @@ import (
"context"
"errors"
"fmt"
- "net/url"
- "strconv"
"strings"
"time"
- "github.com/cenkalti/backoff/v4"
"github.com/huaweicloud/huaweicloud-sdk-go-v3/core/auth/basic"
- "github.com/huaweicloud/huaweicloud-sdk-go-v3/core/config"
ces "github.com/huaweicloud/huaweicloud-sdk-go-v3/services/ces/v1"
"github.com/huaweicloud/huaweicloud-sdk-go-v3/services/ces/v1/model"
"github.com/huaweicloud/huaweicloud-sdk-go-v3/services/ces/v1/region"
"go.opentelemetry.io/collector/component"
- "go.opentelemetry.io/collector/config/configretry"
"go.opentelemetry.io/collector/consumer"
"go.opentelemetry.io/collector/receiver"
"go.uber.org/zap"
+ "github.com/open-telemetry/opentelemetry-collector-contrib/internal/huawei"
"github.com/open-telemetry/opentelemetry-collector-contrib/receiver/huaweicloudcesreceiver/internal"
)
@@ -114,7 +110,7 @@ func (rcvr *cesReceiver) createClient() (*ces.CesClient, error) {
return nil, err
}
- httpConfig, err := createHTTPConfig(rcvr.config.HuaweiSessionConfig)
+ httpConfig, err := huawei.CreateHTTPConfig(rcvr.config.HuaweiSessionConfig)
if err != nil {
return nil, err
}
@@ -155,7 +151,7 @@ func (rcvr *cesReceiver) pollMetricsAndConsume(ctx context.Context) error {
}
func (rcvr *cesReceiver) listMetricDefinitions(ctx context.Context) ([]model.MetricInfoList, error) {
- response, err := internal.MakeAPICallWithRetry(
+ response, err := huawei.MakeAPICallWithRetry(
ctx,
rcvr.shutdownChan,
rcvr.logger,
@@ -163,7 +159,7 @@ func (rcvr *cesReceiver) listMetricDefinitions(ctx context.Context) ([]model.Met
return rcvr.client.ListMetrics(&model.ListMetricsRequest{})
},
func(err error) bool { return strings.Contains(err.Error(), requestThrottledErrMsg) },
- newExponentialBackOff(&rcvr.config.BackOffConfig),
+ huawei.NewExponentialBackOff(&rcvr.config.BackOffConfig),
)
if err != nil {
return []model.MetricInfoList{}, err
@@ -235,7 +231,7 @@ func (rcvr *cesReceiver) listDataPoints(ctx context.Context, metricDefinitions [
}
func (rcvr *cesReceiver) listDataPointsForMetric(ctx context.Context, from, to time.Time, infoList model.MetricInfoList) (*model.ShowMetricDataResponse, error) {
- return internal.MakeAPICallWithRetry(
+ return huawei.MakeAPICallWithRetry(
ctx,
rcvr.shutdownChan,
rcvr.logger,
@@ -254,55 +250,10 @@ func (rcvr *cesReceiver) listDataPointsForMetric(ctx context.Context, from, to t
})
},
func(err error) bool { return strings.Contains(err.Error(), requestThrottledErrMsg) },
- newExponentialBackOff(&rcvr.config.BackOffConfig),
+ huawei.NewExponentialBackOff(&rcvr.config.BackOffConfig),
)
}
-func newExponentialBackOff(backOffConfig *configretry.BackOffConfig) *backoff.ExponentialBackOff {
- return &backoff.ExponentialBackOff{
- InitialInterval: backOffConfig.InitialInterval,
- RandomizationFactor: backOffConfig.RandomizationFactor,
- Multiplier: backOffConfig.Multiplier,
- MaxInterval: backOffConfig.MaxInterval,
- MaxElapsedTime: backOffConfig.MaxElapsedTime,
- Stop: backoff.Stop,
- Clock: backoff.SystemClock,
- }
-}
-
-func createHTTPConfig(cfg HuaweiSessionConfig) (*config.HttpConfig, error) {
- if cfg.ProxyAddress == "" {
- return config.DefaultHttpConfig().WithIgnoreSSLVerification(cfg.NoVerifySSL), nil
- }
- proxy, err := configureHTTPProxy(cfg)
- if err != nil {
- return nil, err
- }
- return config.DefaultHttpConfig().WithProxy(proxy), nil
-}
-
-func configureHTTPProxy(cfg HuaweiSessionConfig) (*config.Proxy, error) {
- proxyURL, err := url.Parse(cfg.ProxyAddress)
- if err != nil {
- return nil, err
- }
-
- proxy := config.NewProxy().
- WithSchema(proxyURL.Scheme).
- WithHost(proxyURL.Hostname())
- if len(proxyURL.Port()) > 0 {
- if i, err := strconv.Atoi(proxyURL.Port()); err == nil {
- proxy = proxy.WithPort(i)
- }
- }
-
- // Configure the username and password if the proxy requires authentication
- if len(cfg.ProxyUser) > 0 {
- proxy = proxy.WithUsername(cfg.ProxyUser).WithPassword(cfg.ProxyPassword)
- }
- return proxy, nil
-}
-
func (rcvr *cesReceiver) Shutdown(_ context.Context) error {
if rcvr.cancel != nil {
rcvr.cancel()
diff --git a/receiver/huaweicloudcesreceiver/receiver_test.go b/receiver/huaweicloudcesreceiver/receiver_test.go
index 672eea39c8b8..267f0f699a6d 100644
--- a/receiver/huaweicloudcesreceiver/receiver_test.go
+++ b/receiver/huaweicloudcesreceiver/receiver_test.go
@@ -274,23 +274,3 @@ func TestStartReadingMetrics(t *testing.T) {
})
}
}
-func TestCreateHTTPConfigNoVerifySSL(t *testing.T) {
- cfg, err := createHTTPConfig(HuaweiSessionConfig{NoVerifySSL: true})
- require.NoError(t, err)
- assert.True(t, cfg.IgnoreSSLVerification)
-}
-
-func TestCreateHTTPConfigWithProxy(t *testing.T) {
- cfg, err := createHTTPConfig(HuaweiSessionConfig{
- ProxyAddress: "https://127.0.0.1:8888",
- ProxyUser: "admin",
- ProxyPassword: "pass",
- AccessKey: "123",
- SecretKey: "secret",
- })
- require.NoError(t, err)
- assert.Equal(t, "https", cfg.HttpProxy.Schema)
- assert.Equal(t, "127.0.0.1", cfg.HttpProxy.Host)
- assert.Equal(t, 8888, cfg.HttpProxy.Port)
- assert.False(t, cfg.IgnoreSSLVerification)
-}
diff --git a/receiver/huaweicloudlogsreceiver/Makefile b/receiver/huaweicloudlogsreceiver/Makefile
new file mode 100644
index 000000000000..c1496226e590
--- /dev/null
+++ b/receiver/huaweicloudlogsreceiver/Makefile
@@ -0,0 +1 @@
+include ../../Makefile.Common
\ No newline at end of file
diff --git a/receiver/huaweicloudlogsreceiver/README.md b/receiver/huaweicloudlogsreceiver/README.md
new file mode 100644
index 000000000000..6784086a080d
--- /dev/null
+++ b/receiver/huaweicloudlogsreceiver/README.md
@@ -0,0 +1,205 @@
+# Huawei Cloud LTS Receiver
+
+
+| Status | |
+| ------------- |-----------|
+| Stability | [development]: logs |
+| Distributions | [] |
+| Issues | [![Open issues](https://img.shields.io/github/issues-search/open-telemetry/opentelemetry-collector-contrib?query=is%3Aissue%20is%3Aopen%20label%3Areceiver%2Fhuaweicloudlogs%20&label=open&color=orange&logo=opentelemetry)](https://github.com/open-telemetry/opentelemetry-collector-contrib/issues?q=is%3Aopen+is%3Aissue+label%3Areceiver%2Fhuaweicloudlogs) [![Closed issues](https://img.shields.io/github/issues-search/open-telemetry/opentelemetry-collector-contrib?query=is%3Aissue%20is%3Aclosed%20label%3Areceiver%2Fhuaweicloudlogs%20&label=closed&color=blue&logo=opentelemetry)](https://github.com/open-telemetry/opentelemetry-collector-contrib/issues?q=is%3Aclosed+is%3Aissue+label%3Areceiver%2Fhuaweicloudlogs) |
+| [Code Owners](https://github.com/open-telemetry/opentelemetry-collector-contrib/blob/main/CONTRIBUTING.md#becoming-a-code-owner) | [@heitorganzeli](https://www.github.com/heitorganzeli), [@narcis96](https://www.github.com/narcis96) |
+
+[development]: https://github.com/open-telemetry/opentelemetry-collector#development
+
+
+This receiver contains the implementation of the Huawei Cloud [Log Tank Service](https://www.huaweicloud.com/intl/en-us/product/lts.html) (LTS) receiver for the OpenTelemetry Collector. The receiver collects logs from Huawei Cloud's LTS service and sends them to the OpenTelemetry Collector for processing and exporting.
+
+## Configuration
+
+The following settings are required:
+
+- `project_id`: The ID of the project in Huawei Cloud. This is used to identify which project's logs are to be collected. See [Obtaining a Project ID](https://support.huaweicloud.com/intl/en-us/devg-apisign/api-sign-provide-proid.html).
+
+- `region_id`: The ID of the Huawei Cloud region from which logs are collected. For example, `eu-west-101`. The full list of the available regions can be found [here](https://pkg.go.dev/github.com/huaweicloud/huaweicloud-sdk-go-v3@v0.1.110/services/lts/v2/region).
+
+- `log_group_id`: A string indicating the ID of the log group.
+
+- `log_stream_id`: A string indicating the ID of the log stream. See [Obtaining Log Group and Log Stream IDs](https://support.huaweicloud.com/intl/en-us/api-lts/lts_api_0006.html#section1).
+
+- `no_verify_ssl`: A boolean flag indicating whether SSL verification should be disabled. Set to True to disable SSL verification.
+
+- `access_key`: The access key needed for LTS authentification. Check `Huawei Cloud SDK Authentication Setup` section for more details.
+
+- `secret_key`: The secret key needed for LTS authentification. Check `Huawei Cloud SDK Authentication Setup` section for more details.
+
+The following settings are optional:
+
+- `initial_delay`: The delay before the first collection of logs begins. This is a duration field, such as 5s for 5 seconds.
+
+- `collection_interval` (default = `60s`): This is the interval at which this receiver collects logs. This value must be a string readable by Golang's [time.ParseDuration](https://pkg.go.dev/time#ParseDuration). Valid time units are `ns`, `us` (or `µs`), `ms`, `s`, `m`, `h`. We recommend a polling interval of at least one minute.
+
+- `retry_on_failure`: The following configurations can be used to control the retry policy of the LTS client. The default values are suitable for most deployment scenarios.
+ - `enabled` (default true)
+ - `initial_interval` (default 100ms)
+ - `max_interval` (default 1s)
+ - `max_elapsed_time` (default 15s)
+ - `randomization_factor` (default 0.5)
+ - `multiplier` (default 1.5)
+
+### Example Configuration
+
+```yaml
+receivers:
+ huaweicloudlogsreceiver:
+ collection_interval: 3h
+ initial_delay: 5s
+ access_key: ${env:HUAWEICLOUD_SDK_AK}
+ secret_key: ${env:HUAWEICLOUD_SDK_SK}
+ project_id: project_1
+ region_id: eu-west-101
+ log_group_id: test-group-id
+ log_stream_id: test-stream-id
+ no_verify_ssl: True
+```
+
+The full list of settings exposed for this receiver are documented [here](./config.go).
+
+### Huawei Cloud SDK Authentication Setup
+
+
+To ensure secure authentication, the Access Key (AK) and Secret Key (SK) used by the Huawei Cloud SDK must be stored in environment variables. See [Obtaining an AK/SK](https://support.huaweicloud.com/intl/en-us/devg-apisign/api-sign-provide-aksk.html).
+
+Before running the application, you need to set the environment variables `HUAWEICLOUD_SDK_AK` and `HUAWEICLOUD_SDK_SK` in your local environment. Here’s how you can do it:
+
+1. Open your terminal.
+2. Set the environment variables by executing the following commands:
+
+ ```sh
+ export HUAWEICLOUD_SDK_AK=your-access-key
+ export HUAWEICLOUD_SDK_SK=your-secret-key
+ ```
+
+3. Verify that the variables are set correctly:
+
+ ```sh
+ echo $HUAWEICLOUD_SDK_AK
+ echo $HUAWEICLOUD_SDK_SK
+ ```
+
+## Error handling
+If you encounter any LTS errors, please refer to the [Huawei Cloud Error Codes](https://support.huaweicloud.com/intl/en-us/ae-ad-1-api-lts/lts_api_0021.html).
+
+## Converting LTS Log Representation to OpenTelemetry Log Representation
+
+| Source Field | Target Field | Description |
+|---------------------------|----------------------------------------------------|---------------------------------------------------------------------------------------------------|
+| **Log Content (timestamp)** | `logRecord.observedTimestamp` | The timestamp extracted from the log content. It follows the layout `"2006-01-02/15:04:05"`. Converted to Unix time in nanoseconds. |
+| **Log Content (body)** | `logRecord.body` | The main content of the log. Stored as a string in the OTLP log body. |
+| **Labels (key)** | `logRecord.attributes` | Each label from the LTS log is converted to an attribute in the OTLP log, where the label's key is used as the attribute's key. |
+| **Labels (value)** | `logRecord.attributes` | The corresponding value of each LTS log label key is stored as the attribute's value. |
+| **Line Number** | `logRecord.attributes.lineNum` | The line number from the LTS log, if available. Stored as an attribute with the key `lineNum`. |
+| **Project ID** | `resource.attributes.project.id` | The project ID used in the configuration file of the receiver.. |
+| **Region ID** | `resource.attributes.region.id` | The region id used in the configuration file of the receiver. |
+| **Group ID** | `resource.attributes.group.id` | The log group id used in the configuration file of the receiver. |
+| **Stream ID** | `resource.attributes.stream.id` | The log stream id used in the configuration file of the receiver. |
+| *N/A* | `resource.attributes.cloud.provider` | Set to `"huawei_cloud"` as the cloud provider. |
+| *N/A* | `scopeLogs.scope.name` | Set to `"huawei_cloud_lts"` as the scope name. |
+| *N/A* | `scopeLogs.scope.version` | Set to `"v2"` as the scope version. |
+
+This mapping ensures that logs from Huawei Cloud's LTS can be seamlessly integrated into systems using the OpenTelemetry Protocol for observability.
+
+
+### Notes
+
+- The `timestamp` field in the source is converted from milliseconds to nanoseconds in the target field.
+- Some fields are added in the target format with constant values to provide additional context and metadata.
+
+### Example:
+
+```json
+[
+ {
+ "content": "2020-07-25/14:40:00 this logis Error NO 2",
+ "line_num": "123",
+ "labels": {
+ "hostIP": "192.168.0.156",
+ "hostId": "9787ef31-f171-4eff-ba71-72d580f11f60",
+ "podName": "default_procname",
+ "clusterId": "CONFIG_FILE",
+ "nameSpace":"CONFIG_FILE",
+ "category": "LTS",
+ }
+ },
+ {
+ "content": "2020-07-25/14:50:00 this logis Error NO 3",
+ "line_num": "456",
+ "labels": {
+ "hostIP": "192.168.0.156",
+ "hostId": "9787ef31-f171-4eff-ba71-72d580f11f60",
+ "podName": "default_procname",
+ "clusterId": "CONFIG_FILE",
+ "nameSpace":"CONFIG_FILE",
+ "category": "LTS",
+ }
+ },
+]
+```
+
+converts to
+
+```json
+{
+ "resourceLogs": [
+ {
+ "resource": {
+ "attributes": {
+ "cloud.provider": "huawei_cloud",
+ "project.id": "project1",
+ "region.id": "region1",
+ "group.id": "group1",
+ "stream.id":"stream1"
+ },
+ "scopeLogs": [
+ {
+ "scope": {
+ "name": "huawei_cloud_lts",
+ "version": "v2"
+ },
+ "logRecords": [
+ {
+ "observedTimeUnixNano": "1595688000000000000",
+ "body": {
+ "stringValue": "2020-07-25/14:40:00 this log is Error NO 2"
+ },
+ "attributes": {
+ "hostIP": "192.168.0.156",
+ "hostId": "9787ef31-f171-4eff-ba71-72d580f11f60",
+ "podName": "default_procname",
+ "clusterId": "CONFIG_FILE",
+ "nameSpace":"CONFIG_FILE",
+ "category": "LTS",
+ "lineNum": "123"
+ },
+ },
+ {
+ "observedTimeUnixNano": "1595688600000000000",
+ "body": {
+ "stringValue": "2020-07-25/14:50:00 this log is Error NO 3"
+ },
+ "attributes": {
+ "hostIP": "192.168.0.156",
+ "hostId": "9787ef31-f171-4eff-ba71-72d580f11f60",
+ "podName": "default_procname",
+ "clusterId": "CONFIG_FILE",
+ "nameSpace":"CONFIG_FILE",
+ "category": "LTS",
+ "lineNum": "456"
+ },
+ }
+ ]
+ }
+ ]
+ }
+ }
+ ]
+}
+```
\ No newline at end of file
diff --git a/receiver/huaweicloudlogsreceiver/config.go b/receiver/huaweicloudlogsreceiver/config.go
new file mode 100644
index 000000000000..08207aa4cff5
--- /dev/null
+++ b/receiver/huaweicloudlogsreceiver/config.go
@@ -0,0 +1,70 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+package huaweicloudlogsreceiver // import "github.com/open-telemetry/opentelemetry-collector-contrib/receiver/huaweicloudlogsreceiver"
+
+import (
+ "errors"
+
+ "go.opentelemetry.io/collector/component"
+ "go.opentelemetry.io/collector/config/confighttp"
+ "go.opentelemetry.io/collector/config/configretry"
+ "go.opentelemetry.io/collector/receiver/scraperhelper"
+ "go.uber.org/multierr"
+
+ "github.com/open-telemetry/opentelemetry-collector-contrib/internal/huawei"
+)
+
+var (
+ errMissingGroupID = errors.New(`"log_group_id" is not specified in config`)
+ errMissingStreamID = errors.New(`"log_stream_id" is not specified in config`)
+)
+
+// Config represent a configuration for the CloudWatch logs exporter.
+type Config struct {
+ scraperhelper.ControllerConfig `mapstructure:",squash"`
+ confighttp.ClientConfig `mapstructure:",squash"`
+ // Set of attributes used to configure huawei's LTS SDK connection
+ huawei.HuaweiSessionConfig `mapstructure:",squash"`
+
+ // ProjectID is a string to reference project where logs should be associated with.
+ // If ProjectID is not filled in, the SDK will automatically call the IAM service to query the project id corresponding to the region.
+ ProjectID string `mapstructure:"project_id"`
+
+ // RegionID is the ID of the LTS region.
+ RegionID string `mapstructure:"region_id"`
+
+ // GroupID is the ID of the LTS log group.
+ GroupID string `mapstructure:"log_group_id"`
+
+ // Stream is the ID of the LTS log stream.
+ StreamID string `mapstructure:"log_stream_id"`
+
+ BackOffConfig configretry.BackOffConfig `mapstructure:"retry_on_failure"`
+}
+
+var _ component.Config = (*Config)(nil)
+
+// Validate config
+func (config *Config) Validate() error {
+ var err error
+ if config.ProjectID == "" {
+ err = multierr.Append(err, huawei.ErrMissingProjectID)
+ }
+ if config.RegionID == "" {
+ err = multierr.Append(err, huawei.ErrMissingRegionID)
+ }
+ if config.GroupID == "" {
+ err = multierr.Append(err, errMissingGroupID)
+ }
+ if config.StreamID == "" {
+ err = multierr.Append(err, errMissingStreamID)
+ }
+
+ // Validate that ProxyAddress is provided if ProxyUser or ProxyPassword is set
+ if (config.ProxyUser != "" || config.ProxyPassword != "") && config.ProxyAddress == "" {
+ err = multierr.Append(err, huawei.ErrInvalidProxy)
+ }
+
+ return err
+}
diff --git a/receiver/huaweicloudlogsreceiver/config_test.go b/receiver/huaweicloudlogsreceiver/config_test.go
new file mode 100644
index 000000000000..a35cda55a0ef
--- /dev/null
+++ b/receiver/huaweicloudlogsreceiver/config_test.go
@@ -0,0 +1,117 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+package huaweicloudlogsreceiver
+
+import (
+ "testing"
+ "time"
+
+ "github.com/stretchr/testify/assert"
+ "go.opentelemetry.io/collector/receiver/scraperhelper"
+
+ "github.com/open-telemetry/opentelemetry-collector-contrib/internal/huawei"
+)
+
+func TestConfigValidate(t *testing.T) {
+ tests := []struct {
+ name string
+ config Config
+ expectedError string
+ }{
+ {
+ name: "Valid config",
+ config: Config{
+ ControllerConfig: scraperhelper.ControllerConfig{
+ CollectionInterval: time.Hour,
+ },
+ RegionID: "cn-north-1",
+ ProjectID: "my_project",
+ GroupID: "group-1",
+ StreamID: "stream-1",
+ },
+ expectedError: "",
+ },
+ {
+ name: "Missing region name",
+ config: Config{
+ ControllerConfig: scraperhelper.ControllerConfig{
+ CollectionInterval: time.Hour,
+ },
+ ProjectID: "my_project",
+ },
+ expectedError: huawei.ErrMissingRegionID.Error(),
+ },
+ {
+ name: "Missing project id",
+ config: Config{
+ ControllerConfig: scraperhelper.ControllerConfig{
+ CollectionInterval: time.Hour,
+ },
+ RegionID: "cn-north-1",
+ },
+ expectedError: huawei.ErrMissingProjectID.Error(),
+ },
+ {
+ name: "Proxy user without proxy address",
+ config: Config{
+ HuaweiSessionConfig: huawei.HuaweiSessionConfig{
+ ProxyUser: "user",
+ },
+ ControllerConfig: scraperhelper.ControllerConfig{
+ CollectionInterval: time.Hour,
+ },
+ RegionID: "cn-north-1",
+ ProjectID: "my_project",
+ GroupID: "group-1",
+ StreamID: "stream-1",
+ },
+ expectedError: huawei.ErrInvalidProxy.Error(),
+ },
+ {
+ name: "Proxy password without proxy address",
+ config: Config{
+ HuaweiSessionConfig: huawei.HuaweiSessionConfig{
+ ProxyPassword: "password",
+ },
+ ControllerConfig: scraperhelper.ControllerConfig{
+ CollectionInterval: time.Hour,
+ },
+ RegionID: "cn-north-1",
+ ProjectID: "my_project",
+ GroupID: "group-1",
+ StreamID: "stream-1",
+ },
+ expectedError: huawei.ErrInvalidProxy.Error(),
+ },
+ {
+ name: "Proxy address with proxy user and password",
+ config: Config{
+ HuaweiSessionConfig: huawei.HuaweiSessionConfig{
+ ProxyAddress: "http://proxy.example.com",
+ ProxyUser: "user",
+ ProxyPassword: "password",
+ },
+ ControllerConfig: scraperhelper.ControllerConfig{
+ CollectionInterval: time.Hour,
+ },
+ RegionID: "cn-north-1",
+ ProjectID: "my_project",
+ GroupID: "group-1",
+ StreamID: "stream-1",
+ },
+ expectedError: "",
+ },
+ }
+
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ err := tt.config.Validate()
+ if tt.expectedError == "" {
+ assert.NoError(t, err)
+ } else {
+ assert.ErrorContains(t, err, tt.expectedError)
+ }
+ })
+ }
+}
diff --git a/receiver/huaweicloudlogsreceiver/factory.go b/receiver/huaweicloudlogsreceiver/factory.go
new file mode 100644
index 000000000000..0b8d78e56741
--- /dev/null
+++ b/receiver/huaweicloudlogsreceiver/factory.go
@@ -0,0 +1,50 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+package huaweicloudlogsreceiver // import "github.com/open-telemetry/opentelemetry-collector-contrib/receiver/huaweicloudlogsreceiver"
+
+import (
+ "context"
+ "time"
+
+ "github.com/cenkalti/backoff/v4"
+ "go.opentelemetry.io/collector/component"
+ "go.opentelemetry.io/collector/config/configretry"
+ "go.opentelemetry.io/collector/consumer"
+ "go.opentelemetry.io/collector/receiver"
+
+ "github.com/open-telemetry/opentelemetry-collector-contrib/internal/huawei"
+ "github.com/open-telemetry/opentelemetry-collector-contrib/receiver/huaweicloudlogsreceiver/internal/metadata"
+)
+
+func NewFactory() receiver.Factory {
+ return receiver.NewFactory(
+ metadata.Type,
+ createDefaultConfig,
+ receiver.WithLogs(createLogsReceiver, metadata.LogsStability))
+}
+
+func createDefaultConfig() component.Config {
+ return &Config{
+ BackOffConfig: configretry.BackOffConfig{
+ Enabled: true,
+ InitialInterval: 100 * time.Millisecond,
+ MaxInterval: time.Second,
+ MaxElapsedTime: 15 * time.Second,
+ RandomizationFactor: backoff.DefaultRandomizationFactor,
+ Multiplier: backoff.DefaultMultiplier,
+ },
+ HuaweiSessionConfig: huawei.HuaweiSessionConfig{
+ NoVerifySSL: false,
+ },
+ }
+}
+
+func createLogsReceiver(
+ _ context.Context,
+ params receiver.Settings,
+ cfg component.Config,
+ next consumer.Logs) (receiver.Logs, error) {
+ return newHuaweiCloudLogsReceiver(params, cfg.(*Config), next), nil
+
+}
diff --git a/receiver/huaweicloudlogsreceiver/factory_test.go b/receiver/huaweicloudlogsreceiver/factory_test.go
new file mode 100644
index 000000000000..970a666768af
--- /dev/null
+++ b/receiver/huaweicloudlogsreceiver/factory_test.go
@@ -0,0 +1,43 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+package huaweicloudlogsreceiver
+
+import (
+ "context"
+ "testing"
+ "time"
+
+ "github.com/stretchr/testify/assert"
+ "go.opentelemetry.io/collector/component"
+ "go.opentelemetry.io/collector/component/componenttest"
+ "go.opentelemetry.io/collector/consumer/consumertest"
+ "go.opentelemetry.io/collector/receiver/receivertest"
+)
+
+func TestNewFactory(t *testing.T) {
+ factory := NewFactory()
+ assert.NotNil(t, factory)
+ assert.Equal(t, component.MustNewType("huaweicloudlogsreceiver"), factory.Type())
+}
+
+func TestCreateDefaultConfig(t *testing.T) {
+ factory := NewFactory()
+ config := factory.CreateDefaultConfig()
+ assert.NotNil(t, config)
+ assert.NoError(t, componenttest.CheckConfigStruct(config))
+}
+
+func TestCreateLogsReceiver(t *testing.T) {
+ factory := NewFactory()
+ config := factory.CreateDefaultConfig()
+
+ rConfig := config.(*Config)
+ rConfig.CollectionInterval = 60 * time.Second
+ rConfig.InitialDelay = time.Second
+
+ nextConsumer := new(consumertest.LogsSink)
+ receiver, err := factory.CreateLogsReceiver(context.Background(), receivertest.NewNopSettings(), config, nextConsumer)
+ assert.NoError(t, err)
+ assert.NotNil(t, receiver)
+}
diff --git a/receiver/huaweicloudlogsreceiver/generated_component_test.go b/receiver/huaweicloudlogsreceiver/generated_component_test.go
new file mode 100644
index 000000000000..c6ce35029500
--- /dev/null
+++ b/receiver/huaweicloudlogsreceiver/generated_component_test.go
@@ -0,0 +1,69 @@
+// Code generated by mdatagen. DO NOT EDIT.
+
+package huaweicloudlogsreceiver
+
+import (
+ "context"
+ "testing"
+
+ "github.com/stretchr/testify/require"
+ "go.opentelemetry.io/collector/component"
+ "go.opentelemetry.io/collector/component/componenttest"
+ "go.opentelemetry.io/collector/confmap/confmaptest"
+ "go.opentelemetry.io/collector/consumer/consumertest"
+ "go.opentelemetry.io/collector/receiver"
+ "go.opentelemetry.io/collector/receiver/receivertest"
+)
+
+func TestComponentFactoryType(t *testing.T) {
+ require.Equal(t, "huaweicloudlogsreceiver", NewFactory().Type().String())
+}
+
+func TestComponentConfigStruct(t *testing.T) {
+ require.NoError(t, componenttest.CheckConfigStruct(NewFactory().CreateDefaultConfig()))
+}
+
+func TestComponentLifecycle(t *testing.T) {
+ factory := NewFactory()
+
+ tests := []struct {
+ name string
+ createFn func(ctx context.Context, set receiver.Settings, cfg component.Config) (component.Component, error)
+ }{
+
+ {
+ name: "logs",
+ createFn: func(ctx context.Context, set receiver.Settings, cfg component.Config) (component.Component, error) {
+ return factory.CreateLogsReceiver(ctx, set, cfg, consumertest.NewNop())
+ },
+ },
+ }
+
+ cm, err := confmaptest.LoadConf("metadata.yaml")
+ require.NoError(t, err)
+ cfg := factory.CreateDefaultConfig()
+ sub, err := cm.Sub("tests::config")
+ require.NoError(t, err)
+ require.NoError(t, sub.Unmarshal(&cfg))
+
+ for _, test := range tests {
+ t.Run(test.name+"-shutdown", func(t *testing.T) {
+ c, err := test.createFn(context.Background(), receivertest.NewNopSettings(), cfg)
+ require.NoError(t, err)
+ err = c.Shutdown(context.Background())
+ require.NoError(t, err)
+ })
+ t.Run(test.name+"-lifecycle", func(t *testing.T) {
+ firstRcvr, err := test.createFn(context.Background(), receivertest.NewNopSettings(), cfg)
+ require.NoError(t, err)
+ host := componenttest.NewNopHost()
+ require.NoError(t, err)
+ require.NoError(t, firstRcvr.Start(context.Background(), host))
+ require.NoError(t, firstRcvr.Shutdown(context.Background()))
+ secondRcvr, err := test.createFn(context.Background(), receivertest.NewNopSettings(), cfg)
+ require.NoError(t, err)
+ require.NoError(t, secondRcvr.Start(context.Background(), host))
+ require.NoError(t, secondRcvr.Shutdown(context.Background()))
+ })
+ }
+}
diff --git a/receiver/huaweicloudlogsreceiver/generated_package_test.go b/receiver/huaweicloudlogsreceiver/generated_package_test.go
new file mode 100644
index 000000000000..ed3fa4e318e1
--- /dev/null
+++ b/receiver/huaweicloudlogsreceiver/generated_package_test.go
@@ -0,0 +1,13 @@
+// Code generated by mdatagen. DO NOT EDIT.
+
+package huaweicloudlogsreceiver
+
+import (
+ "testing"
+
+ "go.uber.org/goleak"
+)
+
+func TestMain(m *testing.M) {
+ goleak.VerifyTestMain(m)
+}
diff --git a/receiver/huaweicloudlogsreceiver/go.mod b/receiver/huaweicloudlogsreceiver/go.mod
new file mode 100644
index 000000000000..d71a93ca971a
--- /dev/null
+++ b/receiver/huaweicloudlogsreceiver/go.mod
@@ -0,0 +1,96 @@
+module github.com/open-telemetry/opentelemetry-collector-contrib/receiver/huaweicloudlogsreceiver
+
+go 1.22.3
+
+require (
+ github.com/cenkalti/backoff/v4 v4.3.0
+ github.com/huaweicloud/huaweicloud-sdk-go-v3 v0.1.113
+ github.com/open-telemetry/opentelemetry-collector-contrib/internal/huawei v0.108.0
+ github.com/open-telemetry/opentelemetry-collector-contrib/pkg/golden v0.108.0
+ github.com/open-telemetry/opentelemetry-collector-contrib/pkg/pdatatest v0.107.0
+ github.com/stretchr/testify v1.9.0
+ go.opentelemetry.io/collector/component v0.109.0
+ go.opentelemetry.io/collector/config/confighttp v0.109.0
+ go.opentelemetry.io/collector/config/configretry v1.15.0
+ go.opentelemetry.io/collector/confmap v1.15.0
+ go.opentelemetry.io/collector/consumer v0.109.0
+ go.opentelemetry.io/collector/consumer/consumertest v0.109.0
+ go.opentelemetry.io/collector/pdata v1.15.0
+ go.opentelemetry.io/collector/receiver v0.109.0
+ go.uber.org/goleak v1.3.0
+ go.uber.org/multierr v1.11.0
+ go.uber.org/zap v1.27.0
+)
+
+require (
+ github.com/beorn7/perks v1.0.1 // indirect
+ github.com/cespare/xxhash/v2 v2.3.0 // indirect
+ github.com/davecgh/go-spew v1.1.1 // indirect
+ github.com/felixge/httpsnoop v1.0.4 // indirect
+ github.com/fsnotify/fsnotify v1.7.0 // indirect
+ github.com/go-logr/logr v1.4.2 // indirect
+ github.com/go-logr/stdr v1.2.2 // indirect
+ github.com/go-viper/mapstructure/v2 v2.1.0 // indirect
+ github.com/gogo/protobuf v1.3.2 // indirect
+ github.com/golang/snappy v0.0.4 // indirect
+ github.com/google/uuid v1.6.0 // indirect
+ github.com/hashicorp/go-version v1.7.0 // indirect
+ github.com/json-iterator/go v1.1.12 // indirect
+ github.com/klauspost/compress v1.17.9 // indirect
+ github.com/knadh/koanf/maps v0.1.1 // indirect
+ github.com/knadh/koanf/providers/confmap v0.1.0 // indirect
+ github.com/knadh/koanf/v2 v2.1.1 // indirect
+ github.com/mitchellh/copystructure v1.2.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/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
+ github.com/open-telemetry/opentelemetry-collector-contrib/pkg/pdatautil v0.108.0 // indirect
+ github.com/pmezard/go-difflib v1.0.0 // indirect
+ github.com/prometheus/client_golang v1.20.2 // indirect
+ github.com/prometheus/client_model v0.6.1 // indirect
+ github.com/prometheus/common v0.57.0 // indirect
+ github.com/prometheus/procfs v0.15.1 // indirect
+ github.com/rs/cors v1.11.1 // indirect
+ github.com/stretchr/objx v0.5.2 // indirect
+ github.com/tjfoc/gmsm v1.4.1 // indirect
+ go.mongodb.org/mongo-driver v1.16.1 // indirect
+ go.opentelemetry.io/collector v0.109.0 // indirect
+ go.opentelemetry.io/collector/client v1.15.0 // indirect
+ go.opentelemetry.io/collector/config/configauth v0.109.0 // indirect
+ go.opentelemetry.io/collector/config/configcompression v1.15.0 // indirect
+ go.opentelemetry.io/collector/config/configopaque v1.15.0 // indirect
+ go.opentelemetry.io/collector/config/configtelemetry v0.109.0 // indirect
+ go.opentelemetry.io/collector/config/configtls v1.15.0 // indirect
+ go.opentelemetry.io/collector/config/internal v0.109.0 // indirect
+ go.opentelemetry.io/collector/consumer/consumerprofiles v0.109.0 // indirect
+ go.opentelemetry.io/collector/extension v0.109.0 // indirect
+ go.opentelemetry.io/collector/extension/auth v0.109.0 // indirect
+ go.opentelemetry.io/collector/featuregate v1.15.0 // indirect
+ go.opentelemetry.io/collector/pdata/pprofile v0.109.0 // indirect
+ go.opentelemetry.io/collector/receiver/receiverprofiles v0.109.0 // indirect
+ go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.54.0 // indirect
+ go.opentelemetry.io/otel v1.30.0 // indirect
+ go.opentelemetry.io/otel/exporters/prometheus v0.51.0 // indirect
+ go.opentelemetry.io/otel/metric v1.30.0 // indirect
+ go.opentelemetry.io/otel/sdk v1.29.0 // indirect
+ go.opentelemetry.io/otel/sdk/metric v1.29.0 // indirect
+ go.opentelemetry.io/otel/trace v1.30.0 // indirect
+ golang.org/x/crypto v0.27.0 // indirect
+ golang.org/x/net v0.29.0 // indirect
+ golang.org/x/sys v0.25.0 // indirect
+ golang.org/x/text v0.18.0 // indirect
+ google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1 // indirect
+ google.golang.org/grpc v1.66.1 // indirect
+ google.golang.org/protobuf v1.34.2 // indirect
+ gopkg.in/ini.v1 v1.67.0 // indirect
+ gopkg.in/yaml.v3 v3.0.1 // indirect
+)
+
+replace github.com/open-telemetry/opentelemetry-collector-contrib/internal/huawei => ./../../internal/huawei
+
+replace github.com/open-telemetry/opentelemetry-collector-contrib/pkg/pdatautil => ../../pkg/pdatautil
+
+replace github.com/open-telemetry/opentelemetry-collector-contrib/pkg/pdatatest => ../../pkg/pdatatest
+
+replace github.com/open-telemetry/opentelemetry-collector-contrib/pkg/golden => ../../pkg/golden
diff --git a/receiver/huaweicloudlogsreceiver/go.sum b/receiver/huaweicloudlogsreceiver/go.sum
new file mode 100644
index 000000000000..ae4a2a11a1eb
--- /dev/null
+++ b/receiver/huaweicloudlogsreceiver/go.sum
@@ -0,0 +1,312 @@
+cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
+github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
+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/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8=
+github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
+github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
+github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
+github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
+github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
+github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
+github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
+github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
+github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
+github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
+github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg=
+github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
+github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA=
+github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM=
+github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
+github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY=
+github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
+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-viper/mapstructure/v2 v2.1.0 h1:gHnMa2Y/pIxElCH2GlZZ1lZSsn6XMtufpGyP1XxdC/w=
+github.com/go-viper/mapstructure/v2 v2.1.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM=
+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/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.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.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
+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/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.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
+github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
+github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
+github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
+github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
+github.com/hashicorp/go-version v1.7.0 h1:5tqGy27NaOTB8yJKUZELlFAS/LTKJkrmONwQKeRZfjY=
+github.com/hashicorp/go-version v1.7.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
+github.com/huaweicloud/huaweicloud-sdk-go-v3 v0.1.113 h1:odui9Ua0u1hPfpkutN/tGvtt0ms55I+gQqIdU8K1rlo=
+github.com/huaweicloud/huaweicloud-sdk-go-v3 v0.1.113/go.mod h1:JWz2ujO9X3oU5wb6kXp+DpR2UuDj2SldDbX8T0FSuhI=
+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/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.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk=
+github.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA=
+github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw=
+github.com/knadh/koanf/maps v0.1.1 h1:G5TjmUh2D7G2YWf5SQQqSiHRJEjaicvU0KpypqB3NIs=
+github.com/knadh/koanf/maps v0.1.1/go.mod h1:npD/QZY3V6ghQDdcQzl1W4ICNVTkohC8E73eI2xW4yI=
+github.com/knadh/koanf/providers/confmap v0.1.0 h1:gOkxhHkemwG4LezxxN8DMOFopOPghxRVp7JbIvdvqzU=
+github.com/knadh/koanf/providers/confmap v0.1.0/go.mod h1:2uLhxQzJnyHKfxG927awZC7+fyHFdQkd697K4MdLnIU=
+github.com/knadh/koanf/v2 v2.1.1 h1:/R8eXqasSTsmDCsAyYj+81Wteg8AqrV9CP6gvsTsOmM=
+github.com/knadh/koanf/v2 v2.1.1/go.mod h1:4mnTRbZCK+ALuBXHZMjDfG9y714L7TykVnZkXbMU3Es=
+github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
+github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
+github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
+github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
+github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
+github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
+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/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 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
+github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
+github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc=
+github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
+github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
+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/prometheus/client_golang v1.20.2 h1:5ctymQzZlyOON1666svgwn3s6IKWgfbjsejTMiXIyjg=
+github.com/prometheus/client_golang v1.20.2/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE=
+github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
+github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E=
+github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY=
+github.com/prometheus/common v0.57.0 h1:Ro/rKjwdq9mZn1K5QPctzh+MA4Lp0BuYk5ZZEVhoNcY=
+github.com/prometheus/common v0.57.0/go.mod h1:7uRPFSUTbfZWsJ7MHY56sqt7hLQu3bxXHDnNhl8E9qI=
+github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc=
+github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk=
+github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ=
+github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog=
+github.com/rs/cors v1.11.1 h1:eU3gRzXLRK57F5rKMGMZURNdIG4EoAmX8k94r9wXWHA=
+github.com/rs/cors v1.11.1/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU=
+github.com/stretchr/objx v0.1.0/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/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY=
+github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
+github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
+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.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
+github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
+github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
+github.com/tjfoc/gmsm v1.4.1 h1:aMe1GlZb+0bLjn+cKTPEvvn9oUEBlJitaZiiBwsbgho=
+github.com/tjfoc/gmsm v1.4.1/go.mod h1:j4INPkHWMrhJb38G+J6W4Tw0AbuN8Thu3PbdVYhVcTE=
+github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI=
+github.com/xdg-go/scram v1.1.2/go.mod h1:RT/sEzTbU5y00aCK8UOx6R7YryM0iF1N2MOmC3kKLN4=
+github.com/xdg-go/stringprep v1.0.4/go.mod h1:mPGuuIYwz7CmR2bT9j4GbQqutWS1zV24gijq1dTyGkM=
+github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d/go.mod h1:rHwXgn7JulP+udvsHwJoVG1YGAP6VLg4y9I5dyZdqmA=
+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.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
+go.mongodb.org/mongo-driver v1.12.0/go.mod h1:AZkxhPnFJUoH7kZlFkVKucV20K387miPfm7oimrSmK0=
+go.mongodb.org/mongo-driver v1.16.1 h1:rIVLL3q0IHM39dvE+z2ulZLp9ENZKThVfuvN/IiN4l8=
+go.mongodb.org/mongo-driver v1.16.1/go.mod h1:oB6AhJQvFQL4LEHyXi6aJzQJtBiTQHiAd83l0GdFaiw=
+go.opentelemetry.io/collector v0.109.0 h1:ULnMWuwcy4ix1oP5RFFRcmpEbaU5YabW6nWcLMQQRo0=
+go.opentelemetry.io/collector v0.109.0/go.mod h1:gheyquSOc5E9Y+xsPmpA+PBrpPc+msVsIalY76/ZvnQ=
+go.opentelemetry.io/collector/client v1.15.0 h1:SMUKTntljRmFvB8nCVf6KjbEQ/qm63wi+huDx+Bc/po=
+go.opentelemetry.io/collector/client v1.15.0/go.mod h1:m0MdKbzRIVgyGu70qbJ6TwBmKtblk7cmPqspM45a5yY=
+go.opentelemetry.io/collector/component v0.109.0 h1:AU6eubP1htO8Fvm86uWn66Kw0DMSFhgcRM2cZZTYfII=
+go.opentelemetry.io/collector/component v0.109.0/go.mod h1:jRVFY86GY6JZ61SXvUN69n7CZoTjDTqWyNC+wJJvzOw=
+go.opentelemetry.io/collector/config/configauth v0.109.0 h1:6I2g1dcXD7KCmzXWHaL09I6RSmiCER4b+UARYkmMw3U=
+go.opentelemetry.io/collector/config/configauth v0.109.0/go.mod h1:i36T9K3m7pLSlqMFdy+npY7JxfxSg3wQc8bHNpykLLE=
+go.opentelemetry.io/collector/config/configcompression v1.15.0 h1:HHzus/ahJW2dA6h4S4vs1MwlbOck27Ivk/L3o0V94UA=
+go.opentelemetry.io/collector/config/configcompression v1.15.0/go.mod h1:pnxkFCLUZLKWzYJvfSwZnPrnm0twX14CYj2ADth5xiU=
+go.opentelemetry.io/collector/config/confighttp v0.109.0 h1:6R2+zI1LqFarEnCL4k+1DCsFi+aVeUTbfFOQBk0JBh0=
+go.opentelemetry.io/collector/config/confighttp v0.109.0/go.mod h1:fzvAO2nCnP9XRUiaCBh1AZ2whUf99iQTkEVFCyH+URk=
+go.opentelemetry.io/collector/config/configopaque v1.15.0 h1:J1rmPR1WGro7BNCgni3o+VDoyB7ZqH2/SG1YK+6ujCw=
+go.opentelemetry.io/collector/config/configopaque v1.15.0/go.mod h1:6zlLIyOoRpJJ+0bEKrlZOZon3rOp5Jrz9fMdR4twOS4=
+go.opentelemetry.io/collector/config/configretry v1.15.0 h1:4ZUPrWWh4wiwdlGnss2lZDhvf1xkt8uwHEqmuqovMEs=
+go.opentelemetry.io/collector/config/configretry v1.15.0/go.mod h1:KvQF5cfphq1rQm1dKR4eLDNQYw6iI2fY72NMZVa+0N0=
+go.opentelemetry.io/collector/config/configtelemetry v0.109.0 h1:ItbYw3tgFMU+TqGcDVEOqJLKbbOpfQg3AHD8b22ygl8=
+go.opentelemetry.io/collector/config/configtelemetry v0.109.0/go.mod h1:R0MBUxjSMVMIhljuDHWIygzzJWQyZHXXWIgQNxcFwhc=
+go.opentelemetry.io/collector/config/configtls v1.15.0 h1:imUIYDu6lo7juxxgpJhoMQ+LJRxqQzKvjOcWTo4u0IY=
+go.opentelemetry.io/collector/config/configtls v1.15.0/go.mod h1:T3pOF5UemLzmYgY7QpiZuDRrihJ8lyXB0cDe6j1F1Ek=
+go.opentelemetry.io/collector/config/internal v0.109.0 h1:uAlmO9Gu4Ff5wXXWWn+7XRZKEBjwGE8YdkdJxOlodns=
+go.opentelemetry.io/collector/config/internal v0.109.0/go.mod h1:JJJGJTz1hILaaT+01FxbCFcDvPf2otXqMcWk/s2KvlA=
+go.opentelemetry.io/collector/confmap v1.15.0 h1:KaNVG6fBJXNqEI+/MgZasH0+aShAU1yAkSYunk6xC4E=
+go.opentelemetry.io/collector/confmap v1.15.0/go.mod h1:GrIZ12P/9DPOuTpe2PIS51a0P/ZM6iKtByVee1Uf3+k=
+go.opentelemetry.io/collector/consumer v0.109.0 h1:fdXlJi5Rat/poHPiznM2mLiXjcv1gPy3fyqqeirri58=
+go.opentelemetry.io/collector/consumer v0.109.0/go.mod h1:E7PZHnVe1DY9hYy37toNxr9/hnsO7+LmnsixW8akLQI=
+go.opentelemetry.io/collector/consumer/consumerprofiles v0.109.0 h1:+WZ6MEWQRC6so3IRrW916XK58rI9NnrFHKW/P19jQvc=
+go.opentelemetry.io/collector/consumer/consumerprofiles v0.109.0/go.mod h1:spZ9Dn1MRMPDHHThdXZA5TrFhdOL1wsl0Dw45EBVoVo=
+go.opentelemetry.io/collector/consumer/consumertest v0.109.0 h1:v4w9G2MXGJ/eabCmX1DvQYmxzdysC8UqIxa/BWz7ACo=
+go.opentelemetry.io/collector/consumer/consumertest v0.109.0/go.mod h1:lECt0qOrx118wLJbGijtqNz855XfvJv0xx9GSoJ8qSE=
+go.opentelemetry.io/collector/extension v0.109.0 h1:r/WkSCYGF1B/IpUgbrKTyJHcfn7+A5+mYfp5W7+B4U0=
+go.opentelemetry.io/collector/extension v0.109.0/go.mod h1:WDE4fhiZnt2haxqSgF/2cqrr5H+QjgslN5tEnTBZuXc=
+go.opentelemetry.io/collector/extension/auth v0.109.0 h1:yKUMCUG3IkjuOnHriNj0nqFU2DRdZn3Tvn9eqCI0eTg=
+go.opentelemetry.io/collector/extension/auth v0.109.0/go.mod h1:wOIv49JhXIfol8CRmQvLve05ft3nZQUnTfcnuZKxdbo=
+go.opentelemetry.io/collector/featuregate v1.15.0 h1:8KRWaZaE9hLlyMXnMTvnWtUJnzrBuTI0aLIvxqe8QP0=
+go.opentelemetry.io/collector/featuregate v1.15.0/go.mod h1:47xrISO71vJ83LSMm8+yIDsUbKktUp48Ovt7RR6VbRs=
+go.opentelemetry.io/collector/pdata v1.15.0 h1:q/T1sFpRKJnjDrUsHdJ6mq4uSqViR/f92yvGwDby/gY=
+go.opentelemetry.io/collector/pdata v1.15.0/go.mod h1:2wcsTIiLAJSbqBq/XUUYbi+cP+N87d0jEJzmb9nT19U=
+go.opentelemetry.io/collector/pdata/pprofile v0.109.0 h1:5lobQKeHk8p4WC7KYbzL6ZqqX3eSizsdmp5vM8pQFBs=
+go.opentelemetry.io/collector/pdata/pprofile v0.109.0/go.mod h1:lXIifCdtR5ewO17JAYTUsclMqRp6h6dCowoXHhGyw8Y=
+go.opentelemetry.io/collector/pdata/testdata v0.109.0 h1:gvIqy6juvqFET/6zi+zUOH1KZY/vtEDZW55u7gJ/hEo=
+go.opentelemetry.io/collector/pdata/testdata v0.109.0/go.mod h1:zRttU/F5QMQ6ZXBMXCoSVG3EORTZLTK+UUS0VoMoT44=
+go.opentelemetry.io/collector/receiver v0.109.0 h1:DTOM7xaDl7FUGQIjvjmWZn03JUE+aG4mJzWWfb7S8zw=
+go.opentelemetry.io/collector/receiver v0.109.0/go.mod h1:jeiCHaf3PE6aXoZfHF5Uexg7aztu+Vkn9LVw0YDKm6g=
+go.opentelemetry.io/collector/receiver/receiverprofiles v0.109.0 h1:KKzdIixE/XJWvqdCcNWAOtsEhNKu4waLKJjawjhnPLw=
+go.opentelemetry.io/collector/receiver/receiverprofiles v0.109.0/go.mod h1:FKU+RFkSLWWB3tUUB6vifapZdFp1FoqVYVQ22jpHc8w=
+go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.54.0 h1:TT4fX+nBOA/+LUkobKGW1ydGcn+G3vRw9+g5HwCphpk=
+go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.54.0/go.mod h1:L7UH0GbB0p47T4Rri3uHjbpCFYrVrwc1I25QhNPiGK8=
+go.opentelemetry.io/otel v1.30.0 h1:F2t8sK4qf1fAmY9ua4ohFS/K+FUuOPemHUIXHtktrts=
+go.opentelemetry.io/otel v1.30.0/go.mod h1:tFw4Br9b7fOS+uEao81PJjVMjW/5fvNCbpsDIXqP0pc=
+go.opentelemetry.io/otel/exporters/prometheus v0.51.0 h1:G7uexXb/K3T+T9fNLCCKncweEtNEBMTO+46hKX5EdKw=
+go.opentelemetry.io/otel/exporters/prometheus v0.51.0/go.mod h1:v0mFe5Kk7woIh938mrZBJBmENYquyA0IICrlYm4Y0t4=
+go.opentelemetry.io/otel/metric v1.30.0 h1:4xNulvn9gjzo4hjg+wzIKG7iNFEaBMX00Qd4QIZs7+w=
+go.opentelemetry.io/otel/metric v1.30.0/go.mod h1:aXTfST94tswhWEb+5QjlSqG+cZlmyXy/u8jFpor3WqQ=
+go.opentelemetry.io/otel/sdk v1.29.0 h1:vkqKjk7gwhS8VaWb0POZKmIEDimRCMsopNYnriHyryo=
+go.opentelemetry.io/otel/sdk v1.29.0/go.mod h1:pM8Dx5WKnvxLCb+8lG1PRNIDxu9g9b9g59Qr7hfAAok=
+go.opentelemetry.io/otel/sdk/metric v1.29.0 h1:K2CfmJohnRgvZ9UAj2/FhIf/okdWcNdBwe1m8xFXiSY=
+go.opentelemetry.io/otel/sdk/metric v1.29.0/go.mod h1:6zZLdCl2fkauYoZIOn/soQIDSWFmNSRcICarHfuhNJQ=
+go.opentelemetry.io/otel/trace v1.30.0 h1:7UBkkYzeg3C7kQX8VAidWh2biiQbtAKjyIML8dQ9wmc=
+go.opentelemetry.io/otel/trace v1.30.0/go.mod h1:5EyKqTzzmyqB9bwtCCq6pDLktPK6fmGf/Dph+8VI02o=
+go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
+go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
+go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
+go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
+go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8=
+go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E=
+golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
+golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
+golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
+golang.org/x/crypto v0.0.0-20201012173705-84dcc777aaee/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
+golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
+golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
+golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
+golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
+golang.org/x/crypto v0.27.0 h1:GXm2NjJrPaiv/h1tb2UH8QfgC/hOf/+z0p6PT8o1w7A=
+golang.org/x/crypto v0.27.0/go.mod h1:1Xngt8kV6Dvbssa53Ziq6Eqn0HqbZi5Z6R0ZpwQzt70=
+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/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.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
+golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
+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-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20201010224723-4f7140c49acb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
+golang.org/x/net v0.0.0-20201021035429-f5854403a974/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-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
+golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
+golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
+golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
+golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
+golang.org/x/net v0.29.0 h1:5ORfpBpCs4HzDYoodCDBbwHzdR5UrLBZ3sOnUJmFoHo=
+golang.org/x/net v0.29.0/go.mod h1:gLkgy8jTGERgjzMic6DS9+SP0ajcu6Xu3Orq/SpETg0=
+golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
+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-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-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/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-20190412213103-97732733099d/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-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
+golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
+golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34=
+golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
+golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
+golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
+golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
+golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
+golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk=
+golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY=
+golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
+golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
+golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
+golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
+golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
+golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
+golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
+golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
+golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
+golang.org/x/text v0.18.0 h1:XvMDiNzPAl0jr17s6W9lcaIhGUfUORdGCNsuLmPG224=
+golang.org/x/text v0.18.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
+golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
+golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
+golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
+golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
+golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
+golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
+golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
+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-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
+google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1 h1:pPJltXNxVzT4pK9yD8vR9X75DaWYYmLGMsEvBfFQZzQ=
+google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1/go.mod h1:UqMtugtsSgubUsoxbuAoiCXvqvErP7Gf0so0mK9tHxU=
+google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
+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.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
+google.golang.org/grpc v1.66.1 h1:hO5qAXR19+/Z44hmvIM4dQFMSYX9XcWsByfoxutBpAM=
+google.golang.org/grpc v1.66.1/go.mod h1:s3/l6xSSCURdVfAnL+TqCNMyTDAGN6+lZeVxnZR128Y=
+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.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
+google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg=
+google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw=
+gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
+gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
+gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA=
+gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
+gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/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=
diff --git a/receiver/huaweicloudlogsreceiver/integration_test.go b/receiver/huaweicloudlogsreceiver/integration_test.go
new file mode 100644
index 000000000000..b2535f485aef
--- /dev/null
+++ b/receiver/huaweicloudlogsreceiver/integration_test.go
@@ -0,0 +1,87 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+package huaweicloudlogsreceiver // import "github.com/open-telemetry/opentelemetry-collector-contrib/receiver/huaweicloudlogsreceiver"
+
+import (
+ "context"
+ "path/filepath"
+ "testing"
+ "time"
+
+ "github.com/huaweicloud/huaweicloud-sdk-go-v3/services/lts/v2/model"
+ "github.com/stretchr/testify/mock"
+ "github.com/stretchr/testify/require"
+ "go.opentelemetry.io/collector/component/componenttest"
+ "go.opentelemetry.io/collector/consumer/consumertest"
+ "go.opentelemetry.io/collector/receiver/receivertest"
+
+ "github.com/open-telemetry/opentelemetry-collector-contrib/pkg/golden"
+ "github.com/open-telemetry/opentelemetry-collector-contrib/pkg/pdatatest/plogtest"
+ "github.com/open-telemetry/opentelemetry-collector-contrib/receiver/huaweicloudlogsreceiver/internal/mocks"
+)
+
+func TestHuaweiCloudLogsReceiverIntegration(t *testing.T) {
+ mc := mocks.NewLtsClient(t)
+
+ mc.On("ListLogs", mock.Anything).Return(&model.ListLogsResponse{
+ Logs: &[]model.LogContents{
+ {
+ Content: stringPtr("2020-07-25/14:40:00 this log is Error NO 2"),
+ LineNum: stringPtr("123"),
+ Labels: map[string]string{
+ "hostName": "ecs-test1",
+ "hostIP": "192.168.0.106",
+ "containerName": "CONFIG_FILE",
+ "category": "LTS",
+ },
+ },
+ {
+ Content: stringPtr("2020-07-25/14:50:00 this log is Error NO 3"),
+ LineNum: stringPtr("456"),
+ Labels: map[string]string{
+ "hostName": "ecs-test2",
+ "hostIP": "192.168.0.206",
+ "containerName": "CONFIG_FILE",
+ "category": "LTS",
+ },
+ },
+ },
+ }, nil)
+
+ sink := &consumertest.LogsSink{}
+ cfg := createDefaultConfig().(*Config)
+ cfg.RegionID = "us-east-2"
+ cfg.CollectionInterval = time.Second
+ cfg.ProjectID = "my-project"
+ cfg.GroupID = "group-1"
+ cfg.StreamID = "stream-1"
+
+ recv, err := NewFactory().CreateLogsReceiver(
+ context.Background(),
+ receivertest.NewNopSettings(),
+ cfg,
+ sink,
+ )
+ require.NoError(t, err)
+
+ rcvr, ok := recv.(*logsReceiver)
+ require.True(t, ok)
+ rcvr.client = mc
+
+ err = recv.Start(context.Background(), componenttest.NewNopHost())
+ require.NoError(t, err)
+
+ require.Eventually(t, func() bool {
+ return sink.LogRecordCount() > 0
+ }, 5*time.Second, 10*time.Millisecond)
+
+ err = recv.Shutdown(context.Background())
+ require.NoError(t, err)
+
+ logs := sink.AllLogs()[0]
+
+ expectedLogs, err := golden.ReadLogs(filepath.Join("testdata", "golden", "logs_golden.yaml"))
+ require.NoError(t, err)
+ require.NoError(t, plogtest.CompareLogs(expectedLogs, logs, plogtest.IgnoreLogRecordsOrder()))
+}
diff --git a/receiver/huaweicloudlogsreceiver/internal/lts_client.go b/receiver/huaweicloudlogsreceiver/internal/lts_client.go
new file mode 100644
index 000000000000..4af24fc05afc
--- /dev/null
+++ b/receiver/huaweicloudlogsreceiver/internal/lts_client.go
@@ -0,0 +1,16 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+package internal // import "github.com/open-telemetry/opentelemetry-collector-contrib/receiver/huaweicloudlogsreceiver/internal"
+
+import (
+ "github.com/huaweicloud/huaweicloud-sdk-go-v3/services/lts/v2/model"
+)
+
+// The functions of the following interface should have the same signature as the ones from https://github.com/huaweicloud/huaweicloud-sdk-go-v3/blob/v0.1.110/services/lts/v2/lts_client.go
+// Check https://github.com/vektra/mockery on how to install it on your machine.
+//
+//go:generate mockery --name LtsClient --case=underscore --output=./mocks
+type LtsClient interface {
+ ListLogs(request *model.ListLogsRequest) (*model.ListLogsResponse, error)
+}
diff --git a/receiver/huaweicloudlogsreceiver/internal/lts_to_otlp.go b/receiver/huaweicloudlogsreceiver/internal/lts_to_otlp.go
new file mode 100644
index 000000000000..120779044043
--- /dev/null
+++ b/receiver/huaweicloudlogsreceiver/internal/lts_to_otlp.go
@@ -0,0 +1,78 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+package internal // import "github.com/open-telemetry/opentelemetry-collector-contrib/receiver/huaweicloudlogsreceiver/internal"
+
+import (
+ "fmt"
+ "regexp"
+ "time"
+
+ "github.com/huaweicloud/huaweicloud-sdk-go-v3/services/lts/v2/model"
+ "go.opentelemetry.io/collector/pdata/pcommon"
+ "go.opentelemetry.io/collector/pdata/plog"
+)
+
+const (
+ layout = "2006-01-02/15:04:05"
+ // Define the regex pattern to match the timestamp
+ pattern = `(\d{4}-\d{2}-\d{2}/\d{2}:\d{2}:\d{2})`
+)
+
+var (
+ re = regexp.MustCompile(pattern)
+)
+
+// example of log content : "2020-07-25/14:44:43 this log is Error NO 2"
+func extractTimestamp(log string) (time.Time, error) {
+ matches := re.FindStringSubmatch(log)
+ if len(matches) == 0 {
+ return time.Time{}, fmt.Errorf("timestamp not found")
+ }
+
+ // Note: Assumtion is that the date string is using UTC timezone.
+ timestamp, err := time.Parse(layout, matches[0])
+ if err != nil {
+ return time.Time{}, err
+ }
+ return timestamp, nil
+}
+
+func ConvertLTSLogsToOTLP(projectID, regionID, groupID, streamD string, ltsLogs []model.LogContents) plog.Logs {
+ logs := plog.NewLogs()
+ resourceLog := logs.ResourceLogs().AppendEmpty()
+
+ resource := resourceLog.Resource()
+ resourceAttr := resource.Attributes()
+ resourceAttr.PutStr("cloud.provider", "huawei_cloud")
+ resourceAttr.PutStr("project.id", projectID)
+ resourceAttr.PutStr("region.id", regionID)
+ resourceAttr.PutStr("group.id", groupID)
+ resourceAttr.PutStr("stream.id", streamD)
+
+ if len(ltsLogs) == 0 {
+ return logs
+ }
+ scopedLog := resourceLog.ScopeLogs().AppendEmpty()
+ scopedLog.Scope().SetName("huawei_cloud_lts")
+ scopedLog.Scope().SetVersion("v2")
+ for _, ltsLog := range ltsLogs {
+
+ logRecord := scopedLog.LogRecords().AppendEmpty()
+ if ltsLog.Content != nil {
+ content := *ltsLog.Content
+ if ts, err := extractTimestamp(content); err == nil {
+ logRecord.SetObservedTimestamp(pcommon.Timestamp(ts.UnixNano()))
+ }
+ logRecord.Body().SetStr(content)
+ }
+ for key, value := range ltsLog.Labels {
+ logRecord.Attributes().PutStr(key, value)
+ }
+ if ltsLog.LineNum != nil {
+ logRecord.Attributes().PutStr("lineNum", *ltsLog.LineNum)
+ }
+ }
+
+ return logs
+}
diff --git a/receiver/huaweicloudlogsreceiver/internal/lts_to_otlp_test.go b/receiver/huaweicloudlogsreceiver/internal/lts_to_otlp_test.go
new file mode 100644
index 000000000000..9f09b087c1fb
--- /dev/null
+++ b/receiver/huaweicloudlogsreceiver/internal/lts_to_otlp_test.go
@@ -0,0 +1,230 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+package internal
+
+import (
+ "testing"
+ "time"
+
+ "github.com/huaweicloud/huaweicloud-sdk-go-v3/services/lts/v2/model"
+ "github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/require"
+ "go.opentelemetry.io/collector/pdata/pcommon"
+)
+
+func mustParseTime(t *testing.T, value string) time.Time {
+ ts, err := time.Parse(layout, value)
+ if err != nil {
+ require.NoError(t, err)
+ }
+ return ts
+}
+
+func TestExtractTimestamp(t *testing.T) {
+ tests := []struct {
+ name string
+ log string
+ expectedTime time.Time
+ expectedError bool
+ }{
+ {
+ name: "Valid Timestamp",
+ log: "2020-07-25/14:44:43 this log is Error NO 2",
+ expectedTime: time.Date(2020, 7, 25, 14, 44, 43, 0, time.UTC),
+ },
+ {
+ name: "Invalid Timestamp Format",
+ log: "2020/07/25 14:44:43 this log is Error NO 2",
+ expectedError: true,
+ },
+ {
+ name: "No Timestamp",
+ log: "this log is Error NO 2",
+ expectedError: true,
+ },
+ {
+ name: "Empty Log",
+ log: "",
+ expectedError: true,
+ },
+ {
+ name: "Partial Timestamp",
+ log: "2020-07-25/14:44 this log is Error NO 2",
+ expectedError: true,
+ },
+ }
+
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ got, err := extractTimestamp(tt.log)
+
+ if (err != nil) != tt.expectedError {
+ t.Errorf("extractTimestamp() error = %v, expectedError %v", err, tt.expectedError)
+ return
+ }
+ if !tt.expectedError && !got.Equal(tt.expectedTime) {
+ t.Errorf("extractTimestamp() = %v, expected %v", got, tt.expectedTime)
+ }
+ })
+ }
+}
+
+func TestConvertLTSLogsToOTLP(t *testing.T) {
+ tests := []struct {
+ name string
+ projectID string
+ regionID string
+ groupID string
+ streamID string
+ ltsLogs []model.LogContents
+ expectLogs int
+ expectedTime time.Time
+ }{
+ {
+ name: "Valid log content with timestamp",
+ projectID: "project1",
+ regionID: "region1",
+ groupID: "group1",
+ streamID: "stream1",
+ ltsLogs: []model.LogContents{
+ {
+ Content: stringPointer("2020-07-25/14:40:00 this log is Error NO 2"),
+ LineNum: stringPointer("123"),
+ Labels: map[string]string{
+ "hostName": "ecs-kwxtest",
+ "hostIP": "192.168.0.156",
+ "appName": "default_appname",
+ "containerName": "CONFIG_FILE",
+ "clusterName": "CONFIG_FILE",
+ "hostId": "9787ef31-f171-4eff-ba71-72d580f11f60",
+ "podName": "default_procname",
+ "clusterId": "CONFIG_FILE",
+ "nameSpace": "CONFIG_FILE",
+ "category": "LTS",
+ },
+ },
+ {
+ Content: stringPointer("2020-07-25/14:50:00 this log is Error NO 2"),
+ LineNum: stringPointer("456"),
+ Labels: map[string]string{
+ "hostName": "ecs-kwxtest",
+ "hostIP": "192.168.0.156",
+ "appName": "default_appname",
+ "containerName": "CONFIG_FILE",
+ "clusterName": "CONFIG_FILE",
+ "hostId": "9787ef31-f171-4eff-ba71-72d580f11f60",
+ "podName": "default_procname",
+ "clusterId": "CONFIG_FILE",
+ "nameSpace": "CONFIG_FILE",
+ "category": "LTS",
+ },
+ },
+ },
+ expectLogs: 2,
+ expectedTime: mustParseTime(t, "2020-07-25/14:44:43"),
+ },
+ {
+ name: "Log content without timestamp",
+ projectID: "project2",
+ regionID: "region2",
+ groupID: "group2",
+ streamID: "stream2",
+ ltsLogs: []model.LogContents{
+ {
+ Content: stringPointer("this log has no timestamp"),
+ Labels: map[string]string{"level": "info"},
+ LineNum: stringPointer("456"),
+ },
+ },
+ expectLogs: 1,
+ expectedTime: time.Time{},
+ },
+ {
+ name: "Empty log content",
+ projectID: "project3",
+ regionID: "region3",
+ groupID: "group3",
+ streamID: "stream3",
+ ltsLogs: []model.LogContents{
+ {
+ Content: stringPointer(""),
+ Labels: map[string]string{"level": "debug"},
+ LineNum: stringPointer("789"),
+ },
+ },
+ expectLogs: 1,
+ expectedTime: time.Time{},
+ },
+ {
+ name: "Multiple logs",
+ projectID: "project4",
+ regionID: "region4",
+ groupID: "group4",
+ streamID: "stream4",
+ ltsLogs: []model.LogContents{
+ {
+ Content: stringPointer("2020-07-25/14:44:43 log1"),
+ Labels: map[string]string{"level": "error"},
+ LineNum: stringPointer("1"),
+ },
+ {
+ Content: stringPointer("2020-07-25/14:45:43 log2"),
+ Labels: map[string]string{"level": "info"},
+ LineNum: stringPointer("2"),
+ },
+ },
+ expectLogs: 2,
+ expectedTime: time.Time{},
+ },
+ {
+ name: "Invalid timestamp format",
+ projectID: "project5",
+ regionID: "region5",
+ groupID: "group5",
+ streamID: "stream5",
+ ltsLogs: []model.LogContents{
+ {
+ Content: stringPointer("25/07/2020 14:44:43 this log has an invalid timestamp"),
+ Labels: map[string]string{"level": "error"},
+ LineNum: stringPointer("123"),
+ },
+ },
+ expectLogs: 1,
+ expectedTime: time.Time{},
+ },
+ }
+
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ logs := ConvertLTSLogsToOTLP(tt.projectID, tt.regionID, tt.groupID, tt.streamID, tt.ltsLogs)
+
+ require.Equal(t, 1, logs.ResourceLogs().Len())
+ require.Equal(t, 1, logs.ResourceLogs().At(0).ScopeLogs().Len())
+
+ logRecords := logs.ResourceLogs().At(0).ScopeLogs().At(0).LogRecords()
+ assert.Equal(t, tt.expectLogs, logRecords.Len(), "unexpected number of logs")
+
+ for i := 0; i < tt.expectLogs; i++ {
+ logRecord := logRecords.At(i)
+ if tt.ltsLogs[i].Content != nil {
+ content := *tt.ltsLogs[i].Content
+ if ts, err := extractTimestamp(content); err == nil {
+ assert.Equal(t, pcommon.Timestamp(ts.UnixNano()), logRecord.ObservedTimestamp(), "unexpected timestamp in log record")
+ }
+ }
+ // Note: +1 is used because we also add "lineNum" as attribute to the los
+ assert.Equal(t, logRecord.Attributes().Len(), len(tt.ltsLogs[i].Labels)+1)
+ for key, value := range tt.ltsLogs[i].Labels {
+ attr, found := logRecord.Attributes().Get(key)
+ assert.True(t, found, "expected attribute %s not found", key)
+ assert.Equal(t, value, attr.Str(), "unexpected value for attribute %s", key)
+ }
+ }
+ })
+ }
+}
+
+func stringPointer(s string) *string {
+ return &s
+}
diff --git a/receiver/huaweicloudlogsreceiver/internal/metadata/generated_status.go b/receiver/huaweicloudlogsreceiver/internal/metadata/generated_status.go
new file mode 100644
index 000000000000..6ec59b8b2775
--- /dev/null
+++ b/receiver/huaweicloudlogsreceiver/internal/metadata/generated_status.go
@@ -0,0 +1,16 @@
+// Code generated by mdatagen. DO NOT EDIT.
+
+package metadata
+
+import (
+ "go.opentelemetry.io/collector/component"
+)
+
+var (
+ Type = component.MustNewType("huaweicloudlogsreceiver")
+ ScopeName = "github.com/open-telemetry/opentelemetry-collector-contrib/receiver/huaweicloudlogsreceiver"
+)
+
+const (
+ LogsStability = component.StabilityLevelDevelopment
+)
diff --git a/receiver/huaweicloudlogsreceiver/internal/mocks/lts_client.go b/receiver/huaweicloudlogsreceiver/internal/mocks/lts_client.go
new file mode 100644
index 000000000000..32865bd87791
--- /dev/null
+++ b/receiver/huaweicloudlogsreceiver/internal/mocks/lts_client.go
@@ -0,0 +1,57 @@
+// Code generated by mockery v2.44.1. DO NOT EDIT.
+
+package mocks
+
+import (
+ model "github.com/huaweicloud/huaweicloud-sdk-go-v3/services/lts/v2/model"
+ mock "github.com/stretchr/testify/mock"
+)
+
+// LtsClient is an autogenerated mock type for the LtsClient type
+type LtsClient struct {
+ mock.Mock
+}
+
+// ListLogs provides a mock function with given fields: request
+func (_m *LtsClient) ListLogs(request *model.ListLogsRequest) (*model.ListLogsResponse, error) {
+ ret := _m.Called(request)
+
+ if len(ret) == 0 {
+ panic("no return value specified for ListLogs")
+ }
+
+ var r0 *model.ListLogsResponse
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*model.ListLogsRequest) (*model.ListLogsResponse, error)); ok {
+ return rf(request)
+ }
+ if rf, ok := ret.Get(0).(func(*model.ListLogsRequest) *model.ListLogsResponse); ok {
+ r0 = rf(request)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*model.ListLogsResponse)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*model.ListLogsRequest) error); ok {
+ r1 = rf(request)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// NewLtsClient creates a new instance of LtsClient. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
+// The first argument is typically a *testing.T value.
+func NewLtsClient(t interface {
+ mock.TestingT
+ Cleanup(func())
+}) *LtsClient {
+ mock := &LtsClient{}
+ mock.Mock.Test(t)
+
+ t.Cleanup(func() { mock.AssertExpectations(t) })
+
+ return mock
+}
diff --git a/receiver/huaweicloudlogsreceiver/metadata.yaml b/receiver/huaweicloudlogsreceiver/metadata.yaml
new file mode 100644
index 000000000000..b3f516ad2f16
--- /dev/null
+++ b/receiver/huaweicloudlogsreceiver/metadata.yaml
@@ -0,0 +1,9 @@
+type: huaweicloudlogsreceiver
+
+status:
+ class: receiver
+ stability:
+ development: [logs]
+ distributions: []
+ codeowners:
+ active: [heitorganzeli, narcis96]
diff --git a/receiver/huaweicloudlogsreceiver/receiver.go b/receiver/huaweicloudlogsreceiver/receiver.go
new file mode 100644
index 000000000000..ff383735f687
--- /dev/null
+++ b/receiver/huaweicloudlogsreceiver/receiver.go
@@ -0,0 +1,192 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+package huaweicloudlogsreceiver // import "github.com/open-telemetry/opentelemetry-collector-contrib/receiver/huaweicloudlogsreceiver"
+
+import (
+ "context"
+ "errors"
+ "strconv"
+ "strings"
+ "time"
+
+ "github.com/huaweicloud/huaweicloud-sdk-go-v3/core/auth/basic"
+ lts "github.com/huaweicloud/huaweicloud-sdk-go-v3/services/lts/v2"
+ "github.com/huaweicloud/huaweicloud-sdk-go-v3/services/lts/v2/model"
+ "github.com/huaweicloud/huaweicloud-sdk-go-v3/services/lts/v2/region"
+ "go.opentelemetry.io/collector/component"
+ "go.opentelemetry.io/collector/consumer"
+ "go.opentelemetry.io/collector/receiver"
+ "go.uber.org/zap"
+
+ "github.com/open-telemetry/opentelemetry-collector-contrib/internal/huawei"
+ "github.com/open-telemetry/opentelemetry-collector-contrib/receiver/huaweicloudlogsreceiver/internal"
+)
+
+const (
+ // See https://support.huaweicloud.com/intl/en-us/devg-apisign/api-sign-errorcode.html
+ requestThrottledErrMsg = "APIGW.0308"
+)
+
+type logsReceiver struct {
+ logger *zap.Logger
+ client internal.LtsClient
+ cancel context.CancelFunc
+
+ host component.Host
+ nextConsumer consumer.Logs
+ lastTs time.Time
+ config *Config
+ shutdownChan chan struct{}
+}
+
+func newHuaweiCloudLogsReceiver(settings receiver.Settings, cfg *Config, next consumer.Logs) *logsReceiver {
+ rcvr := &logsReceiver{
+ logger: settings.Logger,
+ config: cfg,
+ nextConsumer: next,
+ shutdownChan: make(chan struct{}, 1),
+ }
+ return rcvr
+}
+
+func (rcvr *logsReceiver) Start(ctx context.Context, host component.Host) error {
+ rcvr.host = host
+ ctx, rcvr.cancel = context.WithCancel(ctx)
+
+ if rcvr.client == nil {
+ client, err := rcvr.createClient()
+ if err != nil {
+ rcvr.logger.Error(err.Error())
+ return nil
+ }
+ rcvr.client = client
+ }
+
+ go rcvr.startReadingLogs(ctx)
+ return nil
+}
+
+func (rcvr *logsReceiver) startReadingLogs(ctx context.Context) {
+ if rcvr.config.InitialDelay > 0 {
+ <-time.After(rcvr.config.InitialDelay)
+ }
+ if err := rcvr.pollLogsAndConsume(ctx); err != nil {
+ rcvr.logger.Error(err.Error())
+ }
+ ticker := time.NewTicker(rcvr.config.CollectionInterval)
+
+ defer ticker.Stop()
+ for {
+ select {
+ case <-ticker.C:
+ // TODO: Improve error handling for client-server interactions
+ // The current implementation lacks robust error handling, especially for
+ // scenarios such as service unavailability, timeouts, and request errors.
+ // - Investigate how to handle service unavailability or timeouts gracefully.
+ // - Implement appropriate actions or retries for different types of request errors.
+ // - Refer to the Huawei SDK documentation to identify
+ // all possible client/request errors and determine how to manage them.
+ // - Consider implementing custom error messages or fallback mechanisms for critical failures.
+
+ if err := rcvr.pollLogsAndConsume(ctx); err != nil {
+ rcvr.logger.Error(err.Error())
+ }
+ case <-ctx.Done():
+ return
+ }
+ }
+}
+
+func (rcvr *logsReceiver) createClient() (*lts.LtsClient, error) {
+ auth, err := basic.NewCredentialsBuilder().
+ WithAk(string(rcvr.config.AccessKey)).
+ WithSk(string(rcvr.config.SecretKey)).
+ WithProjectId(rcvr.config.ProjectID).
+ SafeBuild()
+
+ if err != nil {
+ return nil, err
+ }
+
+ httpConfig, err := huawei.CreateHTTPConfig(rcvr.config.HuaweiSessionConfig)
+ if err != nil {
+ return nil, err
+ }
+ r, err := region.SafeValueOf(rcvr.config.RegionID)
+ if err != nil {
+ return nil, err
+ }
+
+ hcHTTPConfig, err := lts.LtsClientBuilder().
+ WithRegion(r).
+ WithCredential(auth).
+ WithHttpConfig(httpConfig).
+ SafeBuild()
+
+ if err != nil {
+ return nil, err
+ }
+
+ return lts.NewLtsClient(hcHTTPConfig), nil
+}
+
+func (rcvr *logsReceiver) pollLogsAndConsume(ctx context.Context) error {
+ if rcvr.client == nil {
+ return errors.New("invalid client")
+ }
+ to := time.Now()
+ from := rcvr.lastTs
+ if from.IsZero() {
+ from = to.Add(-1 * rcvr.config.CollectionInterval)
+ }
+ logs, err := rcvr.listLogs(ctx, from, to)
+ if err != nil {
+ return err
+ }
+ config := rcvr.config
+ otpLogs := internal.ConvertLTSLogsToOTLP(config.ProjectID, config.RegionID, config.GroupID, config.StreamID, logs)
+ if err := rcvr.nextConsumer.ConsumeLogs(ctx, otpLogs); err != nil {
+ return err
+ }
+ rcvr.lastTs = to
+ return nil
+}
+
+func (rcvr *logsReceiver) listLogs(ctx context.Context, from, to time.Time) ([]model.LogContents, error) {
+ // TODO: Add pagination logic. Check IsQueryComplete field
+ response, err := huawei.MakeAPICallWithRetry(
+ ctx,
+ rcvr.shutdownChan,
+ rcvr.logger,
+ func() (*model.ListLogsResponse, error) {
+ return rcvr.client.ListLogs(&model.ListLogsRequest{
+ LogGroupId: "test",
+ LogStreamId: "test",
+ Body: &model.QueryLtsLogParams{
+ StartTime: strconv.FormatInt(from.UTC().UnixMilli(), 10),
+ EndTime: strconv.FormatInt(to.UTC().UnixMilli(), 10),
+ },
+ })
+ },
+ func(err error) bool { return strings.Contains(err.Error(), requestThrottledErrMsg) },
+ huawei.NewExponentialBackOff(&rcvr.config.BackOffConfig),
+ )
+ if err != nil {
+ return []model.LogContents{}, err
+ }
+ if response == nil || response.Logs == nil || len((*response.Logs)) == 0 {
+ return []model.LogContents{}, errors.New("unexpected empty list of logs")
+ }
+
+ return *response.Logs, nil
+}
+
+func (rcvr *logsReceiver) Shutdown(_ context.Context) error {
+ if rcvr.cancel != nil {
+ rcvr.cancel()
+ }
+ rcvr.shutdownChan <- struct{}{}
+ close(rcvr.shutdownChan)
+ return nil
+}
diff --git a/receiver/huaweicloudlogsreceiver/receiver_test.go b/receiver/huaweicloudlogsreceiver/receiver_test.go
new file mode 100644
index 000000000000..40ecf5d9c172
--- /dev/null
+++ b/receiver/huaweicloudlogsreceiver/receiver_test.go
@@ -0,0 +1,114 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+package huaweicloudlogsreceiver // import "github.com/open-telemetry/opentelemetry-collector-contrib/receiver/huaweicloudlogsreceiver"
+
+import (
+ "context"
+ "errors"
+ "testing"
+ "time"
+
+ "github.com/huaweicloud/huaweicloud-sdk-go-v3/services/lts/v2/model"
+ "github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/mock"
+ "github.com/stretchr/testify/require"
+ "go.opentelemetry.io/collector/consumer/consumertest"
+ "go.opentelemetry.io/collector/receiver/receivertest"
+ "go.opentelemetry.io/collector/receiver/scraperhelper"
+
+ "github.com/open-telemetry/opentelemetry-collector-contrib/receiver/huaweicloudlogsreceiver/internal/mocks"
+)
+
+func stringPtr(s string) *string {
+ return &s
+}
+
+func TestNewReceiver(t *testing.T) {
+ cfg := &Config{
+ ControllerConfig: scraperhelper.ControllerConfig{
+ CollectionInterval: 1 * time.Second,
+ },
+ }
+ mr := newHuaweiCloudLogsReceiver(receivertest.NewNopSettings(), cfg, new(consumertest.LogsSink))
+ assert.NotNil(t, mr)
+}
+
+func TestListLogsSuccess(t *testing.T) {
+ mc := mocks.NewLtsClient(t)
+
+ mc.On("ListLogs", mock.Anything).Return(&model.ListLogsResponse{
+ Logs: &[]model.LogContents{
+ {
+ Content: stringPtr("2020-07-25/14:40:43 this log is Error NO 2"),
+ LineNum: stringPtr("10"),
+ Labels: map[string]string{
+ "hostName": "ecs-kwxtest",
+ "hostIP": "192.168.0.156",
+ "appName": "default_appname",
+ "containerName": "CONFIG_FILE",
+ "clusterName": "CONFIG_FILE",
+ "hostId": "9787ef31-fd7b-4eff-ba71-72d580f11f55",
+ "podName": "default_procname",
+ "clusterId": "CONFIG_FILE",
+ "nameSpace": "CONFIG_FILE",
+ "category": "LTS",
+ },
+ },
+ {
+ Content: stringPtr("2020-07-26/15:00:43 this log is Error NO 3"),
+ },
+ },
+ }, nil)
+
+ receiver := &logsReceiver{
+ client: mc,
+ config: createDefaultConfig().(*Config),
+ }
+
+ logs, err := receiver.listLogs(context.Background(), time.Now(), time.Now())
+
+ assert.NoError(t, err)
+ assert.Len(t, logs, 2)
+ mc.AssertExpectations(t)
+}
+
+func TestListLogsFailure(t *testing.T) {
+ mc := mocks.NewLtsClient(t)
+
+ mc.On("ListLogs", mock.Anything).Return(nil, errors.New("failed to list logs"))
+ receiver := &logsReceiver{
+ client: mc,
+ config: createDefaultConfig().(*Config),
+ }
+
+ logs, err := receiver.listLogs(context.Background(), time.Now(), time.Now())
+
+ assert.Error(t, err)
+ assert.Empty(t, logs)
+ assert.Equal(t, "failed to list logs", err.Error())
+ mc.AssertExpectations(t)
+}
+
+func TestPollLogsAndConsumeSuccess(t *testing.T) {
+ mc := mocks.NewLtsClient(t)
+ next := new(consumertest.LogsSink)
+ receiver := newHuaweiCloudLogsReceiver(receivertest.NewNopSettings(), &Config{}, next)
+ receiver.client = mc
+
+ mc.On("ListLogs", mock.Anything).Return(&model.ListLogsResponse{
+ Logs: &[]model.LogContents{
+ {
+ Content: stringPtr("2020-07-25/14:40:43 this log is Error NO 2"),
+ },
+ {
+ Content: stringPtr("2020-07-26/15:00:43 this log is Error NO 3"),
+ },
+ },
+ }, nil)
+
+ err := receiver.pollLogsAndConsume(context.Background())
+
+ require.NoError(t, err)
+ assert.Equal(t, 2, next.LogRecordCount())
+}
diff --git a/receiver/huaweicloudlogsreceiver/testdata/golden/logs_golden.yaml b/receiver/huaweicloudlogsreceiver/testdata/golden/logs_golden.yaml
new file mode 100644
index 000000000000..d9dd79935100
--- /dev/null
+++ b/receiver/huaweicloudlogsreceiver/testdata/golden/logs_golden.yaml
@@ -0,0 +1,62 @@
+resourceLogs:
+ - resource:
+ attributes:
+ - key: cloud.provider
+ value:
+ stringValue: huawei_cloud
+ - key: project.id
+ value:
+ stringValue: my-project
+ - key: region.id
+ value:
+ stringValue: us-east-2
+ - key: group.id
+ value:
+ stringValue: group-1
+ - key: stream.id
+ value:
+ stringValue: stream-1
+ scopeLogs:
+ - logRecords:
+ - attributes:
+ - key: hostName
+ value:
+ stringValue: "ecs-test1"
+ - key: hostIP
+ value:
+ stringValue: "192.168.0.106"
+ - key: containerName
+ value:
+ stringValue: "CONFIG_FILE"
+ - key: category
+ value:
+ stringValue: "LTS"
+ - key: lineNum
+ value:
+ stringValue: "123"
+ body:
+ stringValue: '2020-07-25/14:40:00 this log is Error NO 2'
+ observedTimeUnixNano: "1595688000000000000"
+ - attributes:
+ - key: hostName
+ value:
+ stringValue: "ecs-test2"
+ - key: hostIP
+ value:
+ stringValue: "192.168.0.206"
+ - key: containerName
+ value:
+ stringValue: "CONFIG_FILE"
+ - key: category
+ value:
+ stringValue: "LTS"
+ - key: lineNum
+ value:
+ stringValue: "456"
+ body:
+ stringValue: '2020-07-25/14:50:00 this log is Error NO 3'
+ observedTimeUnixNano: "1595688600000000000"
+ scope:
+ name: huawei_cloud_lts
+ version: v2
+
diff --git a/versions.yaml b/versions.yaml
index 201f0e269d3e..7319f9e5ddfb 100644
--- a/versions.yaml
+++ b/versions.yaml
@@ -127,6 +127,7 @@ module-sets:
- github.com/open-telemetry/opentelemetry-collector-contrib/internal/exp/metrics
- github.com/open-telemetry/opentelemetry-collector-contrib/internal/filter
- github.com/open-telemetry/opentelemetry-collector-contrib/internal/grpcutil
+ - github.com/open-telemetry/opentelemetry-collector-contrib/internal/huawei
- github.com/open-telemetry/opentelemetry-collector-contrib/internal/k8sconfig
- github.com/open-telemetry/opentelemetry-collector-contrib/internal/k8stest
- github.com/open-telemetry/opentelemetry-collector-contrib/internal/kafka