diff --git a/aitelemetry/connection_string_parser.go b/aitelemetry/connection_string_parser.go new file mode 100644 index 0000000000..b4e7223a22 --- /dev/null +++ b/aitelemetry/connection_string_parser.go @@ -0,0 +1,52 @@ +package aitelemetry + +import ( + "strings" + + "github.com/pkg/errors" +) + +type connectionVars struct { + instrumentationKey string + ingestionURL string +} + +func (c *connectionVars) String() string { + return "InstrumentationKey=" + c.instrumentationKey + ";IngestionEndpoint=" + c.ingestionURL +} + +func parseConnectionString(connectionString string) (*connectionVars, error) { + connectionVars := &connectionVars{} + + if connectionString == "" { + return nil, errors.New("connection string cannot be empty") + } + + pairs := strings.Split(connectionString, ";") + for _, pair := range pairs { + kv := strings.SplitN(pair, "=", 2) + if len(kv) != 2 { + return nil, errors.Errorf("invalid connection string format: %s", pair) + } + key, value := strings.TrimSpace(kv[0]), strings.TrimSpace(kv[1]) + + if key == "" { + return nil, errors.Errorf("key in connection string cannot be empty") + } + + switch strings.ToLower(key) { + case "instrumentationkey": + connectionVars.instrumentationKey = value + case "ingestionendpoint": + if value != "" { + connectionVars.ingestionURL = value + "v2.1/track" + } + } + } + + if connectionVars.instrumentationKey == "" || connectionVars.ingestionURL == "" { + return nil, errors.Errorf("missing required fields in connection string: %s", connectionVars) + } + + return connectionVars, nil +} diff --git a/aitelemetry/connection_string_parser_test.go b/aitelemetry/connection_string_parser_test.go new file mode 100644 index 0000000000..adac67cd06 --- /dev/null +++ b/aitelemetry/connection_string_parser_test.go @@ -0,0 +1,66 @@ +package aitelemetry + +import ( + "testing" + + "github.com/stretchr/testify/require" +) + +const connectionString = "InstrumentationKey=0000-0000-0000-0000-0000;IngestionEndpoint=https://ingestion.endpoint.com/;LiveEndpoint=https://live.endpoint.com/;ApplicationId=1111-1111-1111-1111-1111" + +func TestParseConnectionString(t *testing.T) { + tests := []struct { + name string + connectionString string + want *connectionVars + wantErr bool + }{ + { + name: "Valid connection string and instrumentation key", + connectionString: connectionString, + want: &connectionVars{ + instrumentationKey: "0000-0000-0000-0000-0000", + ingestionURL: "https://ingestion.endpoint.com/v2.1/track", + }, + wantErr: false, + }, + { + name: "Invalid connection string format", + connectionString: "InvalidConnectionString", + want: nil, + wantErr: true, + }, + { + name: "Valid instrumentation key with missing ingestion endpoint", + connectionString: "InstrumentationKey=0000-0000-0000-0000-0000;IngestionEndpoint=", + want: nil, + wantErr: true, + }, + { + name: "Missing instrumentation key with valid ingestion endpoint", + connectionString: "InstrumentationKey=;IngestionEndpoint=https://ingestion.endpoint.com/", + want: nil, + wantErr: true, + }, + { + name: "Empty connection string", + connectionString: "", + want: nil, + wantErr: true, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := parseConnectionString(tt.connectionString) + if tt.wantErr { + require.Error(t, err, "Expected error but got none") + } else { + require.NoError(t, err, "Expected no error but got one") + require.NotNil(t, got, "Expected a non-nil result") + require.Equal(t, tt.want.instrumentationKey, got.instrumentationKey, "Instrumentation Key does not match") + require.Equal(t, tt.want.ingestionURL, got.ingestionURL, "Ingestion URL does not match") + } + }) + } +} diff --git a/aitelemetry/telemetrywrapper.go b/aitelemetry/telemetrywrapper.go index 39deebb802..20dde0baa2 100644 --- a/aitelemetry/telemetrywrapper.go +++ b/aitelemetry/telemetrywrapper.go @@ -13,6 +13,7 @@ import ( "github.com/Azure/azure-container-networking/store" "github.com/microsoft/ApplicationInsights-Go/appinsights" "github.com/microsoft/ApplicationInsights-Go/appinsights/contracts" + "github.com/pkg/errors" ) const ( @@ -161,7 +162,7 @@ func isPublicEnvironment(url string, retryCount, waitTimeInSecs int) (bool, erro return true, nil } else if err == nil { debugLog("[AppInsights] This is not azure public cloud:%s", cloudName) - return false, fmt.Errorf("Not an azure public cloud: %s", cloudName) + return false, errors.Errorf("not an azure public cloud: %s", cloudName) } debugLog("GetAzureCloud returned err :%v", err) @@ -214,6 +215,46 @@ func NewAITelemetry( return th, nil } +// NewWithConnectionString creates telemetry handle with user specified appinsights connection string. +func NewWithConnectionString(connectionString string, aiConfig AIConfig) (TelemetryHandle, error) { + debugMode = aiConfig.DebugMode + + if connectionString == "" { + debugLog("Empty connection string") + return nil, errors.New("AI connection string is empty") + } + + setAIConfigDefaults(&aiConfig) + + connectionVars, err := parseConnectionString(connectionString) + if err != nil { + debugLog("Error parsing connection string: %v", err) + return nil, err + } + + telemetryConfig := appinsights.NewTelemetryConfiguration(connectionVars.instrumentationKey) + telemetryConfig.EndpointUrl = connectionVars.ingestionURL + telemetryConfig.MaxBatchSize = aiConfig.BatchSize + telemetryConfig.MaxBatchInterval = time.Duration(aiConfig.BatchInterval) * time.Second + + th := &telemetryHandle{ + client: appinsights.NewTelemetryClientFromConfig(telemetryConfig), + appName: aiConfig.AppName, + appVersion: aiConfig.AppVersion, + diagListener: messageListener(), + disableMetadataRefreshThread: aiConfig.DisableMetadataRefreshThread, + refreshTimeout: aiConfig.RefreshTimeout, + } + + if th.disableMetadataRefreshThread { + getMetadata(th) + } else { + go getMetadata(th) + } + + return th, nil +} + // TrackLog function sends report (trace) to appinsights resource. It overrides few of the existing columns with app information // and for rest it uses custom dimesion func (th *telemetryHandle) TrackLog(report Report) { diff --git a/aitelemetry/telemetrywrapper_test.go b/aitelemetry/telemetrywrapper_test.go index 2ccb175217..363f9b90a8 100644 --- a/aitelemetry/telemetrywrapper_test.go +++ b/aitelemetry/telemetrywrapper_test.go @@ -15,7 +15,7 @@ import ( ) var ( - th TelemetryHandle + aiConfig AIConfig hostAgentUrl = "localhost:3501" getCloudResponse = "AzurePublicCloud" httpURL = "http://" + hostAgentUrl @@ -54,6 +54,18 @@ func TestMain(m *testing.M) { return } + aiConfig = AIConfig{ + AppName: "testapp", + AppVersion: "v1.0.26", + BatchSize: 4096, + BatchInterval: 2, + RefreshTimeout: 10, + GetEnvRetryCount: 1, + GetEnvRetryWaitTimeInSecs: 2, + DebugMode: true, + DisableMetadataRefreshThread: true, + } + exitCode := m.Run() if runtime.GOOS == "linux" { @@ -75,45 +87,50 @@ func handleGetCloud(w http.ResponseWriter, req *http.Request) { w.Write([]byte(getCloudResponse)) } +func initTelemetry(_ *testing.T) (th1, th2 TelemetryHandle) { + th1, err1 := NewAITelemetry(httpURL, "00ca2a73-c8d6-4929-a0c2-cf84545ec225", aiConfig) + if err1 != nil { + fmt.Printf("Error initializing AI telemetry: %v", err1) + } + + th2, err2 := NewWithConnectionString(connectionString, aiConfig) + if err2 != nil { + fmt.Printf("Error initializing AI telemetry with connection string: %v", err2) + } + + return +} + func TestEmptyAIKey(t *testing.T) { var err error - aiConfig := AIConfig{ - AppName: "testapp", - AppVersion: "v1.0.26", - BatchSize: 4096, - BatchInterval: 2, - RefreshTimeout: 10, - DebugMode: true, - DisableMetadataRefreshThread: true, - } _, err = NewAITelemetry(httpURL, "", aiConfig) if err == nil { - t.Errorf("Error intializing AI telemetry:%v", err) + t.Errorf("Error initializing AI telemetry:%v", err) + } + + _, err = NewWithConnectionString("", aiConfig) + if err == nil { + t.Errorf("Error initializing AI telemetry with connection string:%v", err) } } func TestNewAITelemetry(t *testing.T) { var err error - aiConfig := AIConfig{ - AppName: "testapp", - AppVersion: "v1.0.26", - BatchSize: 4096, - BatchInterval: 2, - RefreshTimeout: 10, - GetEnvRetryCount: 1, - GetEnvRetryWaitTimeInSecs: 2, - DebugMode: true, - DisableMetadataRefreshThread: true, + th1, th2 := initTelemetry(t) + if th1 == nil { + t.Errorf("Error initializing AI telemetry: %v", err) } - th, err = NewAITelemetry(httpURL, "00ca2a73-c8d6-4929-a0c2-cf84545ec225", aiConfig) - if th == nil { - t.Errorf("Error intializing AI telemetry: %v", err) + + if th2 == nil { + t.Errorf("Error initializing AI telemetry with connection string: %v", err) } } func TestTrackMetric(t *testing.T) { + th1, th2 := initTelemetry(t) + metric := Metric{ Name: "test", Value: 1.0, @@ -121,10 +138,13 @@ func TestTrackMetric(t *testing.T) { } metric.CustomDimensions["dim1"] = "col1" - th.TrackMetric(metric) + th1.TrackMetric(metric) + th2.TrackMetric(metric) } func TestTrackLog(t *testing.T) { + th1, th2 := initTelemetry(t) + report := Report{ Message: "test", Context: "10a", @@ -132,10 +152,13 @@ func TestTrackLog(t *testing.T) { } report.CustomDimensions["dim1"] = "col1" - th.TrackLog(report) + th1.TrackLog(report) + th2.TrackLog(report) } func TestTrackEvent(t *testing.T) { + th1, th2 := initTelemetry(t) + event := Event{ EventName: "testEvent", ResourceID: "SomeResourceId", @@ -144,35 +167,20 @@ func TestTrackEvent(t *testing.T) { event.Properties["P1"] = "V1" event.Properties["P2"] = "V2" - th.TrackEvent(event) + th1.TrackEvent(event) + th2.TrackEvent(event) } func TestFlush(t *testing.T) { - th.Flush() -} + th1, th2 := initTelemetry(t) -func TestClose(t *testing.T) { - th.Close(10) + th1.Flush() + th2.Flush() } -func TestClosewithoutSend(t *testing.T) { - var err error - - aiConfig := AIConfig{ - AppName: "testapp", - AppVersion: "v1.0.26", - BatchSize: 4096, - BatchInterval: 2, - DisableMetadataRefreshThread: true, - RefreshTimeout: 10, - GetEnvRetryCount: 1, - GetEnvRetryWaitTimeInSecs: 2, - } - - thtest, err := NewAITelemetry(httpURL, "00ca2a73-c8d6-4929-a0c2-cf84545ec225", aiConfig) - if thtest == nil { - t.Errorf("Error intializing AI telemetry:%v", err) - } +func TestClose(t *testing.T) { + th1, th2 := initTelemetry(t) - thtest.Close(10) + th1.Close(10) + th2.Close(10) } diff --git a/go.mod b/go.mod index beafd879a3..bd9bc4255b 100644 --- a/go.mod +++ b/go.mod @@ -25,7 +25,7 @@ require ( github.com/microsoft/ApplicationInsights-Go v0.4.4 github.com/nxadm/tail v1.4.11 github.com/onsi/ginkgo v1.16.5 - github.com/onsi/gomega v1.34.1 + github.com/onsi/gomega v1.37.0 github.com/patrickmn/go-cache v2.1.0+incompatible github.com/pkg/errors v0.9.1 github.com/prometheus/client_golang v1.22.0 @@ -52,7 +52,7 @@ require ( ) require ( - code.cloudfoundry.org/clock v1.0.0 // indirect + code.cloudfoundry.org/clock v1.41.0 // indirect github.com/Azure/azure-sdk-for-go/sdk/internal v1.11.1 // indirect github.com/Azure/azure-sdk-for-go/sdk/keyvault/internal v0.7.1 // indirect github.com/AzureAD/microsoft-authentication-library-for-go v1.4.2 // indirect @@ -62,11 +62,11 @@ require ( github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/evanphx/json-patch v5.7.0+incompatible // indirect github.com/fsnotify/fsnotify v1.9.0 - github.com/go-logr/logr v1.4.2 // indirect + github.com/go-logr/logr v1.4.3 // indirect github.com/go-openapi/jsonpointer v0.20.2 // indirect github.com/go-openapi/jsonreference v0.20.4 // indirect github.com/go-openapi/swag v0.22.7 // indirect - github.com/gofrs/uuid v4.2.0+incompatible // indirect + github.com/gofrs/uuid v4.4.0+incompatible // indirect github.com/gogo/protobuf v1.3.2 // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/google/gofuzz v1.2.0 // indirect @@ -223,6 +223,7 @@ require ( go.opentelemetry.io/proto/otlp v1.3.1 // indirect go.uber.org/dig v1.17.1 // indirect go.yaml.in/yaml/v2 v2.4.2 // indirect + go.yaml.in/yaml/v3 v3.0.4 // indirect go4.org/netipx v0.0.0-20231129151722-fdeea329fbba // indirect google.golang.org/genproto/googleapis/api v0.0.0-20250324211829-b45e905df463 // indirect k8s.io/apiserver v0.30.14 // indirect diff --git a/go.sum b/go.sum index ec544070f7..3d9308f7c9 100644 --- a/go.sum +++ b/go.sum @@ -4,8 +4,8 @@ cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMT cloud.google.com/go/compute/metadata v0.6.0 h1:A6hENjEsCDtC1k8byVsgwvVcioamEHvZ4j01OwKxG9I= cloud.google.com/go/compute/metadata v0.6.0/go.mod h1:FjyFAW1MW0C203CEOMDTu3Dk1FlqW3Rga40jzHL4hfg= code.cloudfoundry.org/clock v0.0.0-20180518195852-02e53af36e6c/go.mod h1:QD9Lzhd/ux6eNQVUDVRJX/RKTigpewimNYBi7ivZKY8= -code.cloudfoundry.org/clock v1.0.0 h1:kFXWQM4bxYvdBw2X8BbBeXwQNgfoWv1vqAk2ZZyBN2o= -code.cloudfoundry.org/clock v1.0.0/go.mod h1:QD9Lzhd/ux6eNQVUDVRJX/RKTigpewimNYBi7ivZKY8= +code.cloudfoundry.org/clock v1.41.0 h1:YiYQSEqcxswK+YtQ+NRIE31E1VNXkwb53Bb3zRmsoOM= +code.cloudfoundry.org/clock v1.41.0/go.mod h1:ncX4UpMuVwZooK7Rw7P+fsE2brLasFbPlibOOrZq40w= github.com/AdaLogics/go-fuzz-headers v0.0.0-20230811130428-ced1acdcaa24 h1:bvDV9vkmnHYOMsOr4WLk+Vo07yKIzd94sVoIqshQ4bU= github.com/AdaLogics/go-fuzz-headers v0.0.0-20230811130428-ced1acdcaa24/go.mod h1:8o94RPi1/7XTJvwPpRSzSUedZrtlirdB3r9Z20bi2f8= github.com/Azure/azure-container-networking/zapai v0.0.3 h1:73druF1cnne5Ign/ztiXP99Ss5D+UJ80EL2mzPgNRhk= @@ -167,8 +167,8 @@ github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0= github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas= 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/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI= +github.com/go-logr/logr v1.4.3/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-logr/zapr v1.3.0 h1:XGdV8XW8zdwFiwOA2Dryh1gj2KRQyOOoNmBy4EplIcQ= @@ -215,8 +215,8 @@ github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5x github.com/godbus/dbus/v5 v5.1.0 h1:4KLkAxT3aOY8Li4FRJe/KvhoNFFxo0m6fNuFUO8QJUk= github.com/godbus/dbus/v5 v5.1.0/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/gofrs/uuid v3.3.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= -github.com/gofrs/uuid v4.2.0+incompatible h1:yyYWMnhkhrKwwr8gAOcOCYxOOscHgDS9yZgBrnJfGa0= -github.com/gofrs/uuid v4.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= +github.com/gofrs/uuid v4.4.0+incompatible h1:3qXRTX8/NbyulANqlc0lchS1gqAVxRgsuW1YrTJupqA= +github.com/gofrs/uuid v4.4.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/golang-jwt/jwt v3.2.1+incompatible h1:73Z+4BJcrTC+KczS6WvTPvRGOp1WmfEP4Q1lOd9Z/+c= @@ -269,8 +269,8 @@ github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gopacket v1.1.19 h1:ves8RnFZPGiFnTS0uPQStjwru6uO6h+nlr9j6fL7kF8= github.com/google/gopacket v1.1.19/go.mod h1:iJ8V8n6KS+z2U1A8pUwu8bW5SyEMkXJB8Yo/Vo+TKTo= -github.com/google/pprof v0.0.0-20240727154555-813a5fbdbec8 h1:FKHo8hFI3A+7w0aUQuYXQ+6EN5stWmeY/AZqtM8xk9k= -github.com/google/pprof v0.0.0-20240727154555-813a5fbdbec8/go.mod h1:K1liHPHnj73Fdn/EKuT8nrFqBihUSKXoLYU0BuatOYo= +github.com/google/pprof v0.0.0-20250630185457-6e76a2b096b5 h1:xhMrHhTJ6zxu3gA4enFM9MLn9AY7613teCdFnlUVbSQ= +github.com/google/pprof v0.0.0-20250630185457-6e76a2b096b5/go.mod h1:5hDyRhoBCxViHszMt12TnOpEI4VVi+U8Gm9iphldiMA= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= @@ -391,8 +391,8 @@ github.com/oklog/ulid v1.3.1 h1:EGfNDEx6MqHz8B3uNV6QAib1UR2Lm97sHi3ocA6ESJ4= github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= github.com/onsi/ginkgo v1.12.0 h1:Iw5WCbBcaAAd0fpRb1c9r5YCylv4XDoCSigm1zLevwU= github.com/onsi/ginkgo v1.12.0/go.mod h1:oUhWkIvk5aDxtKvDDuw8gItl8pKl42LzjC9KZE0HfGg= -github.com/onsi/ginkgo/v2 v2.20.1 h1:YlVIbqct+ZmnEph770q9Q7NVAz4wwIiVNahee6JyUzo= -github.com/onsi/ginkgo/v2 v2.20.1/go.mod h1:lG9ey2Z29hR41WMVthyJBGUBcBhGOtoPF2VFMvBXFCI= +github.com/onsi/ginkgo/v2 v2.23.4 h1:ktYTpKJAVZnDT4VjxSbiBenUjmlL/5QkBEocaWXiQus= +github.com/onsi/ginkgo/v2 v2.23.4/go.mod h1:Bt66ApGPBFzHyR+JO10Zbt0Gsp4uWxu5mIOTusL46e8= github.com/onsi/gomega v1.10.0 h1:Gwkk+PTu/nfOwNMtUB/mRUv0X7ewW5dO4AERT1ThVKo= github.com/onsi/gomega v1.10.0/go.mod h1:Ho0h+IUsWyvy1OpqCwxlQ/21gkhVunqlU8fDGcoTdcA= github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= @@ -564,6 +564,8 @@ go.opentelemetry.io/otel/trace v1.35.0 h1:dPpEfJu1sDIqruz7BHFG3c7528f6ddfSWfFDVt go.opentelemetry.io/otel/trace v1.35.0/go.mod h1:WUk7DtFp1Aw2MkvqGdwiXYDZZNvA/1J8o6xRXLrIkyc= go.opentelemetry.io/proto/otlp v1.3.1 h1:TrMUixzpM0yuc/znrFTP9MMRh8trP93mkCiDVeXrui0= go.opentelemetry.io/proto/otlp v1.3.1/go.mod h1:0X1WI4de4ZsLrrJNLAQbFeLCm3T7yBkR0XqQ7niQU+8= +go.uber.org/automaxprocs v1.6.0 h1:O3y2/QNTOdbF+e/dpXNNW7Rx2hZ4sTIPyybbxyNqTUs= +go.uber.org/automaxprocs v1.6.0/go.mod h1:ifeIMSnPZuznNm6jmdzmU3/bfk01Fe2fotchwEFJ8r8= go.uber.org/dig v1.17.1 h1:Tga8Lz8PcYNsWsyHMZ1Vm0OQOUaJNDyvPImgbAu9YSc= go.uber.org/dig v1.17.1/go.mod h1:Us0rSJiThwCv2GteUN0Q7OKvU7n5J4dxZ9JKUXozFdE= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= @@ -574,8 +576,8 @@ go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8= go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= go.yaml.in/yaml/v2 v2.4.2 h1:DzmwEr2rDGHl7lsFgAHxmNz/1NlQ7xLIrlN2h5d1eGI= go.yaml.in/yaml/v2 v2.4.2/go.mod h1:081UH+NErpNdqlCXm3TtEran0rJZGxAYx9hb/ELlsPU= -go.yaml.in/yaml/v3 v3.0.3 h1:bXOww4E/J3f66rav3pX3m8w6jDE4knZjGOw8b5Y6iNE= -go.yaml.in/yaml/v3 v3.0.3/go.mod h1:tBHosrYAkRZjRAOREWbDnBXUf08JOwYq++0QNwQiWzI= +go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc= +go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= go4.org/netipx v0.0.0-20231129151722-fdeea329fbba h1:0b9z3AuHCjxk0x/opv64kcgZLBseWJUpBw5I82+2U4M= go4.org/netipx v0.0.0-20231129151722-fdeea329fbba/go.mod h1:PLyyIXexvUFg3Owu6p/WfdlivPbZJsZdgWZlrGope/Y= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= @@ -676,8 +678,8 @@ golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roY golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= -golang.org/x/tools v0.33.0 h1:4qz2S3zmRxbGIhDIAgjxvFutSvH5EfnsYrRBj0UI0bc= -golang.org/x/tools v0.33.0/go.mod h1:CIJMaWEY88juyUfo7UbgPqbC8rU2OqfAV1h2Qp0oMYI= +golang.org/x/tools v0.34.0 h1:qIpSLOxeCYGg9TrcJokLBG4KFA6d795g0xkBkiESGlo= +golang.org/x/tools v0.34.0/go.mod h1:pAP9OwEaY1CAW3HOmg3hLZC5Z0CCmzjAF2UQMSqNARg= 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=