From cabe322e3ae0c9ba7c6fa1e953f03a5ec42b7da1 Mon Sep 17 00:00:00 2001 From: Maxence Maireaux Date: Thu, 21 Mar 2024 09:59:13 +0100 Subject: [PATCH] chore: Remove Analytics --- .github/workflows/main.yml | 4 - .github/workflows/template_docker.yaml | 6 - .../workflows/template_goreleaser-build.yaml | 5 - .../template_goreleaser-release.yaml | 5 - .goreleaser-darwin.yml | 1 - .goreleaser.yml | 3 - Dockerfile | 2 - cmd/container.go | 2 - cmd/internal/analytics.go | 89 -------- cmd/internal/analytics_test.go | 170 -------------- cmd/root.go | 8 +- go.mod | 28 +-- go.sum | 52 ++--- libs/analytics/cli.go | 67 ------ libs/analytics/cli_test.go | 103 --------- libs/analytics/module.go | 55 ----- libs/analytics/module_test.go | 85 ------- libs/analytics/segment.go | 126 ---------- libs/analytics/segment_test.go | 166 -------------- pkg/analytics/segment.go | 215 ------------------ pkg/analytics/segment_test.go | 177 -------------- 21 files changed, 30 insertions(+), 1339 deletions(-) delete mode 100644 cmd/internal/analytics.go delete mode 100644 cmd/internal/analytics_test.go delete mode 100644 libs/analytics/cli.go delete mode 100644 libs/analytics/cli_test.go delete mode 100644 libs/analytics/module.go delete mode 100644 libs/analytics/module_test.go delete mode 100644 libs/analytics/segment.go delete mode 100644 libs/analytics/segment_test.go delete mode 100644 pkg/analytics/segment.go delete mode 100644 pkg/analytics/segment_test.go diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index bdf1528a4..4452ddc16 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -53,7 +53,6 @@ jobs: uses: ./.github/workflows/template_goreleaser-build.yaml secrets: NUMARY_GITHUB_TOKEN: ${{ secrets.NUMARY_GITHUB_TOKEN }} - SEGMENT_WRITE_KEY_OSS: ${{ secrets.SEGMENT_WRITE_KEY_OSS }} GoReleaserRelease: needs: @@ -65,7 +64,6 @@ jobs: uses: ./.github/workflows/template_goreleaser-release.yaml secrets: NUMARY_GITHUB_TOKEN: ${{ secrets.NUMARY_GITHUB_TOKEN }} - SEGMENT_WRITE_KEY_OSS: ${{ secrets.SEGMENT_WRITE_KEY_OSS }} FURY_TOKEN: ${{ secrets.FURY_TOKEN }} SdkGenerate: @@ -97,7 +95,6 @@ jobs: RELEASE: ${{ github.event.action }} secrets: NUMARY_GITHUB_TOKEN: ${{ secrets.NUMARY_GITHUB_TOKEN }} - SEGMENT_WRITE_KEY_OSS: ${{ secrets.SEGMENT_WRITE_KEY_OSS }} DockerBranch: needs: @@ -112,4 +109,3 @@ jobs: RELEASE: ${{ github.event.action }} secrets: NUMARY_GITHUB_TOKEN: ${{ secrets.NUMARY_GITHUB_TOKEN }} - SEGMENT_WRITE_KEY_OSS: ${{ secrets.SEGMENT_WRITE_KEY_OSS }} diff --git a/.github/workflows/template_docker.yaml b/.github/workflows/template_docker.yaml index 50f774c0f..922ffcbb3 100644 --- a/.github/workflows/template_docker.yaml +++ b/.github/workflows/template_docker.yaml @@ -18,9 +18,6 @@ on: NUMARY_GITHUB_TOKEN: required: true description: GitHub token with access to the repo - SEGMENT_WRITE_KEY_OSS: - required: true - description: Segment write key for the OSS repo jobs: Docker: @@ -54,7 +51,6 @@ jobs: build-args: | APP_SHA=${{ inputs.APP_SHA }} VERSION=${{ inputs.VERSION }} - SEGMENT_WRITE_KEY=${{ secrets.SEGMENT_WRITE_KEY_OSS }} - name: Build and push PreReleased if: inputs.RELEASE == 'prereleased' uses: docker/build-push-action@v2 @@ -66,7 +62,6 @@ jobs: build-args: | APP_SHA=${{ inputs.APP_SHA }} VERSION=${{ inputs.VERSION }} - SEGMENT_WRITE_KEY=${{ secrets.SEGMENT_WRITE_KEY_OSS }} - name: Build and push if: inputs.RELEASE != 'released' || inputs.RELEASE != 'prereleased' uses: docker/build-push-action@v2 @@ -78,4 +73,3 @@ jobs: build-args: | APP_SHA=${{ inputs.APP_SHA }} VERSION=${{ inputs.VERSION }} - SEGMENT_WRITE_KEY=${{ secrets.SEGMENT_WRITE_KEY_OSS }} diff --git a/.github/workflows/template_goreleaser-build.yaml b/.github/workflows/template_goreleaser-build.yaml index 7e5213284..218aab2c0 100644 --- a/.github/workflows/template_goreleaser-build.yaml +++ b/.github/workflows/template_goreleaser-build.yaml @@ -5,9 +5,6 @@ on: NUMARY_GITHUB_TOKEN: required: true description: GitHub token with access to the repo - SEGMENT_WRITE_KEY_OSS: - required: true - description: Segment write key for the OSS repo jobs: goreleaser: @@ -37,7 +34,6 @@ jobs: args: build --parallelism 4 --rm-dist --skip-validate --snapshot env: GITHUB_TOKEN: ${{ secrets.NUMARY_GITHUB_TOKEN }} - SEGMENT_WRITE_KEY: ${{ secrets.SEGMENT_WRITE_KEY_OSS }} - name: Run GoReleaser for MacOS if: ${{ matrix.os == 'macos-latest' }} uses: goreleaser/goreleaser-action@v4 @@ -46,7 +42,6 @@ jobs: args: build -f .goreleaser-darwin.yml --parallelism 4 --rm-dist --skip-validate --snapshot env: GITHUB_TOKEN: ${{ secrets.NUMARY_GITHUB_TOKEN }} - SEGMENT_WRITE_KEY: ${{ secrets.SEGMENT_WRITE_KEY_OSS }} - uses: actions/upload-artifact@v2 with: name: dist diff --git a/.github/workflows/template_goreleaser-release.yaml b/.github/workflows/template_goreleaser-release.yaml index 63dbf8bae..5a0244d5a 100644 --- a/.github/workflows/template_goreleaser-release.yaml +++ b/.github/workflows/template_goreleaser-release.yaml @@ -5,9 +5,6 @@ on: NUMARY_GITHUB_TOKEN: required: true description: GitHub token with access to the repo - SEGMENT_WRITE_KEY_OSS: - required: true - description: Segment write key for the OSS repo FURY_TOKEN: required: true description: Fury token for the OSS repo @@ -41,7 +38,6 @@ jobs: env: GITHUB_TOKEN: ${{ secrets.NUMARY_GITHUB_TOKEN }} FURY_TOKEN: ${{ secrets.FURY_TOKEN }} - SEGMENT_WRITE_KEY: ${{ secrets.SEGMENT_WRITE_KEY_OSS }} uses: goreleaser/goreleaser-action@v4 with: version: latest @@ -51,7 +47,6 @@ jobs: env: GITHUB_TOKEN: ${{ secrets.NUMARY_GITHUB_TOKEN }} FURY_TOKEN: ${{ secrets.FURY_TOKEN }} - SEGMENT_WRITE_KEY: ${{ secrets.SEGMENT_WRITE_KEY_OSS }} uses: goreleaser/goreleaser-action@v4 with: version: latest diff --git a/.goreleaser-darwin.yml b/.goreleaser-darwin.yml index f72c4b051..fc40b9208 100644 --- a/.goreleaser-darwin.yml +++ b/.goreleaser-darwin.yml @@ -13,7 +13,6 @@ builds: - -X github.com/numary/ledger/cmd.BuildDate={{ .Date }} - -X github.com/numary/ledger/cmd.Version={{ .Version }} - -X github.com/numary/ledger/cmd.Commit={{ .ShortCommit }} - - -X github.com/numary/ledger/cmd.DefaultSegmentWriteKey={{ .Env.SEGMENT_WRITE_KEY }} - -s env: - CGO_ENABLED=1 diff --git a/.goreleaser.yml b/.goreleaser.yml index 07e9a80ec..67ecb026a 100644 --- a/.goreleaser.yml +++ b/.goreleaser.yml @@ -13,7 +13,6 @@ builds: - -X github.com/numary/ledger/cmd.BuildDate={{ .Date }} - -X github.com/numary/ledger/cmd.Version={{ .Version }} - -X github.com/numary/ledger/cmd.Commit={{ .ShortCommit }} - - -X github.com/numary/ledger/cmd.DefaultSegmentWriteKey={{ .Env.SEGMENT_WRITE_KEY }} env: - CGO_ENABLED=1 - CC=x86_64-w64-mingw32-gcc @@ -29,7 +28,6 @@ builds: - -X github.com/numary/ledger/cmd.BuildDate={{ .Date }} - -X github.com/numary/ledger/cmd.Version={{ .Version }} - -X github.com/numary/ledger/cmd.Commit={{ .ShortCommit }} - - -X github.com/numary/ledger/cmd.DefaultSegmentWriteKey={{ .Env.SEGMENT_WRITE_KEY }} - -extldflags "-static" env: - CGO_ENABLED=1 @@ -45,7 +43,6 @@ builds: - -X github.com/numary/ledger/cmd.BuildDate={{ .Date }} - -X github.com/numary/ledger/cmd.Version={{ .Version }} - -X github.com/numary/ledger/cmd.Commit={{ .ShortCommit }} - - -X github.com/numary/ledger/cmd.DefaultSegmentWriteKey={{ .Env.SEGMENT_WRITE_KEY }} - -extldflags "-static" env: - CGO_ENABLED=1 diff --git a/Dockerfile b/Dockerfile index c20edde39..84f367f47 100644 --- a/Dockerfile +++ b/Dockerfile @@ -8,7 +8,6 @@ RUN CGO_ENABLED=1 GOOS=linux go install -v -installsuffix cgo -a std ARG TARGETARCH ARG APP_SHA ARG VERSION -ARG SEGMENT_WRITE_KEY WORKDIR /go/src/github.com/numary/ledger # get deps first so it's cached COPY . . @@ -20,7 +19,6 @@ RUN --mount=type=cache,id=gobuild,target=/root/.cache/go-build \ -ldflags="-X github.com/numary/ledger/cmd.Version=${VERSION} \ -X github.com/numary/ledger/cmd.BuildDate=$(date +%s) \ -X github.com/numary/ledger/cmd.Commit=${APP_SHA} \ - -X github.com/numary/ledger/cmd.DefaultSegmentWriteKey=${SEGMENT_WRITE_KEY}" ./ FROM ubuntu:jammy as app RUN apt update && apt install -y ca-certificates wget && rm -rf /var/lib/apt/lists/* diff --git a/cmd/container.go b/cmd/container.go index 7c187eea6..1ff73d57e 100644 --- a/cmd/container.go +++ b/cmd/container.go @@ -92,8 +92,6 @@ func resolveOptions(v *viper.Viper, userOptions ...fx.Option) []fx.Option { RedisLockStrategy: redisLockStrategy, })) - options = append(options, internal.NewAnalyticsModule(v, Version)) - options = append(options, fx.Provide( fx.Annotate(func() []ledger.LedgerOption { ledgerOptions := []ledger.LedgerOption{} diff --git a/cmd/internal/analytics.go b/cmd/internal/analytics.go deleted file mode 100644 index 0a78e01c4..000000000 --- a/cmd/internal/analytics.go +++ /dev/null @@ -1,89 +0,0 @@ -package internal - -import ( - "context" - "time" - - "github.com/Masterminds/semver/v3" - "github.com/formancehq/stack/libs/go-libs/logging" - "github.com/numary/ledger/pkg/analytics" - "github.com/spf13/cobra" - "github.com/spf13/viper" - "go.uber.org/fx" -) - -const ( - // deprecated - segmentEnabledFlag = "segment-enabled" - // deprecated - segmentWriteKeyFlag = "segment-write-key" - // deprecated - segmentApplicationIdFlag = "segment-application-id" - // deprecated - segmentHeartbeatIntervalFlag = "segment-heartbeat-interval" - - telemetryEnabledFlag = "telemetry-enabled" - telemetryWriteKeyFlag = "telemetry-write-key" - telemetryApplicationIdFlag = "telemetry-application-id" - telemetryHeartbeatIntervalFlag = "telemetry-heartbeat-interval" -) - -func InitAnalyticsFlags(cmd *cobra.Command, defaultWriteKey string) { - cmd.PersistentFlags().Bool(segmentEnabledFlag, false, "Is segment enabled") - cmd.PersistentFlags().String(segmentApplicationIdFlag, "", "Segment application id") - cmd.PersistentFlags().String(segmentWriteKeyFlag, defaultWriteKey, "Segment write key") - cmd.PersistentFlags().Duration(segmentHeartbeatIntervalFlag, 4*time.Hour, "Segment heartbeat interval") - cmd.PersistentFlags().Bool(telemetryEnabledFlag, true, "Is telemetry enabled") - cmd.PersistentFlags().String(telemetryApplicationIdFlag, "", "telemetry application id") - cmd.PersistentFlags().String(telemetryWriteKeyFlag, defaultWriteKey, "telemetry write key") - cmd.PersistentFlags().Duration(telemetryHeartbeatIntervalFlag, 4*time.Hour, "telemetry heartbeat interval") -} - -func NewAnalyticsModule(v *viper.Viper, version string) fx.Option { - if v.GetBool(telemetryEnabledFlag) || v.GetBool(segmentEnabledFlag) { - applicationId := viper.GetString(telemetryApplicationIdFlag) - if applicationId == "" { - applicationId = viper.GetString(segmentApplicationIdFlag) - } - var appIdProviderModule fx.Option - if applicationId == "" { - appIdProviderModule = fx.Provide(analytics.FromStorageAppIdProvider) - } else { - appIdProviderModule = fx.Provide(func() analytics.AppIdProvider { - return analytics.AppIdProviderFn(func(ctx context.Context) (string, error) { - return applicationId, nil - }) - }) - } - writeKey := viper.GetString(telemetryWriteKeyFlag) - if writeKey == "" { - writeKey = viper.GetString(segmentWriteKeyFlag) - } - interval := viper.GetDuration(telemetryHeartbeatIntervalFlag) - if interval == 0 { - interval = viper.GetDuration(segmentHeartbeatIntervalFlag) - } - if writeKey == "" { - return fx.Invoke(func(l logging.Logger) { - l.Infof("telemetry enabled but no write key provided") - }) - } else if interval == 0 { - return fx.Invoke(func(l logging.Logger) { - l.Error("telemetry heartbeat interval is 0") - }) - } else { - _, err := semver.NewVersion(version) - if err != nil { - return fx.Invoke(func(l logging.Logger) { - l.Infof("telemetry enabled but version '%s' is not semver, skip", version) - }) - } else { - return fx.Options( - appIdProviderModule, - analytics.NewHeartbeatModule(version, writeKey, interval), - ) - } - } - } - return fx.Options() -} diff --git a/cmd/internal/analytics_test.go b/cmd/internal/analytics_test.go deleted file mode 100644 index b4199a1b0..000000000 --- a/cmd/internal/analytics_test.go +++ /dev/null @@ -1,170 +0,0 @@ -package internal - -import ( - "context" - "net/http" - "os" - "reflect" - "testing" - "time" - - "github.com/numary/ledger/pkg/ledger" - "github.com/numary/ledger/pkg/storage" - "github.com/numary/ledger/pkg/storage/sqlstorage" - "github.com/pborman/uuid" - "github.com/spf13/cobra" - "github.com/spf13/viper" - "github.com/stretchr/testify/require" - "go.uber.org/fx" - "gopkg.in/segmentio/analytics-go.v3" -) - -func TestAnalyticsFlags(t *testing.T) { - type testCase struct { - name string - key string - envValue string - viperMethod interface{} - expectedValue interface{} - } - - for _, testCase := range []testCase{ - { - name: "using deprecated segment enabled flag", - key: segmentEnabledFlag, - envValue: "true", - viperMethod: (*viper.Viper).GetBool, - expectedValue: true, - }, - { - name: "using deprecated segment write key flag", - key: segmentWriteKeyFlag, - envValue: "foo:bar", - viperMethod: (*viper.Viper).GetString, - expectedValue: "foo:bar", - }, - { - name: "using deprecated segment heartbeat interval flag", - key: segmentHeartbeatIntervalFlag, - envValue: "10s", - viperMethod: (*viper.Viper).GetDuration, - expectedValue: 10 * time.Second, - }, - { - name: "using deprecated segment application id flag", - key: segmentApplicationIdFlag, - envValue: "foo:bar", - viperMethod: (*viper.Viper).GetString, - expectedValue: "foo:bar", - }, - { - name: "using telemetry enabled flag", - key: telemetryEnabledFlag, - envValue: "true", - viperMethod: (*viper.Viper).GetBool, - expectedValue: true, - }, - { - name: "using telemetry write key flag", - key: telemetryWriteKeyFlag, - envValue: "foo:bar", - viperMethod: (*viper.Viper).GetString, - expectedValue: "foo:bar", - }, - { - name: "using telemetry heartbeat interval flag", - key: telemetryHeartbeatIntervalFlag, - envValue: "10s", - viperMethod: (*viper.Viper).GetDuration, - expectedValue: 10 * time.Second, - }, - { - name: "using telemetry application id flag", - key: telemetryApplicationIdFlag, - envValue: "foo:bar", - viperMethod: (*viper.Viper).GetString, - expectedValue: "foo:bar", - }, - } { - t.Run(testCase.name, func(t *testing.T) { - v := viper.GetViper() - cmd := &cobra.Command{ - Run: func(cmd *cobra.Command, args []string) { - ret := reflect.ValueOf(testCase.viperMethod).Call([]reflect.Value{ - reflect.ValueOf(v), - reflect.ValueOf(testCase.key), - }) - require.Len(t, ret, 1) - - rValue := ret[0].Interface() - require.Equal(t, testCase.expectedValue, rValue) - }, - } - InitHTTPBasicFlags(cmd) - BindEnv(v) - - restoreEnvVar := setEnvVar(testCase.key, testCase.envValue) - defer restoreEnvVar() - - require.NoError(t, v.BindPFlags(cmd.PersistentFlags())) - require.NoError(t, cmd.Execute()) - }) - } -} - -func TestAnalyticsModule(t *testing.T) { - v := viper.GetViper() - v.Set(telemetryEnabledFlag, true) - v.Set(telemetryWriteKeyFlag, "XXX") - v.Set(telemetryApplicationIdFlag, "appId") - v.Set(telemetryHeartbeatIntervalFlag, 10*time.Second) - - handled := make(chan struct{}) - - module := NewAnalyticsModule(v, "1.0.0") - app := fx.New( - module, - fx.Provide(func(lc fx.Lifecycle) (storage.Driver[ledger.Store], error) { - id := uuid.New() - driver := sqlstorage.NewDriver("sqlite", sqlstorage.NewSQLiteDB(os.TempDir(), id), false) - lc.Append(fx.Hook{ - OnStart: driver.Initialize, - }) - return sqlstorage.NewLedgerStorageDriverFromRawDriver(driver), nil - }), - fx.Replace(analytics.Config{ - BatchSize: 1, - Transport: roundTripperFn(func(req *http.Request) (*http.Response, error) { - select { - case <-handled: - // Nothing to do, the chan has already been closed - default: - close(handled) - } - return &http.Response{ - StatusCode: http.StatusOK, - }, nil - }), - })) - require.NoError(t, app.Start(context.Background())) - defer func() { - require.NoError(t, app.Stop(context.Background())) - }() - - select { - case <-time.After(time.Second): - require.Fail(t, "Timeout waiting first stats from analytics module") - case <-handled: - } - -} - -func TestAnalyticsModuleDisabled(t *testing.T) { - v := viper.GetViper() - v.Set(telemetryEnabledFlag, false) - - module := NewAnalyticsModule(v, "1.0.0") - app := fx.New(module) - require.NoError(t, app.Start(context.Background())) - require.NoError(t, app.Stop(context.Background())) -} diff --git a/cmd/root.go b/cmd/root.go index 43d86bb96..797a57a65 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -49,10 +49,9 @@ const ( ) var ( - Version = "develop" - BuildDate = "-" - Commit = "-" - DefaultSegmentWriteKey = "" + Version = "develop" + BuildDate = "-" + Commit = "-" ) func NewRootCommand() *cobra.Command { @@ -152,7 +151,6 @@ func NewRootCommand() *cobra.Command { otlptraces.InitOTLPTracesFlags(root.PersistentFlags()) internal.InitHTTPBasicFlags(root) - internal.InitAnalyticsFlags(root, DefaultSegmentWriteKey) publish.InitCLIFlags(root) if err = viper.BindPFlags(root.PersistentFlags()); err != nil { diff --git a/go.mod b/go.mod index 6c4c4fcdc..d32c48faf 100755 --- a/go.mod +++ b/go.mod @@ -4,7 +4,6 @@ go 1.19 require ( github.com/DmitriyVTitov/size v1.5.0 - github.com/Masterminds/semver/v3 v3.2.0 github.com/ThreeDotsLabs/watermill v1.2.0 github.com/antlr/antlr4/runtime/Go/antlr v1.4.10 github.com/buger/jsonparser v1.1.1 @@ -18,13 +17,13 @@ require ( github.com/google/go-cmp v0.5.9 github.com/google/uuid v1.3.0 github.com/huandu/go-sqlbuilder v1.19.0 - github.com/jackc/pgx/v5 v5.3.0 + github.com/jackc/pgx/v5 v5.5.5 github.com/lib/pq v1.10.7 github.com/logrusorgru/aurora v2.0.3+incompatible github.com/mattn/go-sqlite3 v1.14.16 github.com/mitchellh/mapstructure v1.5.0 github.com/ory/dockertest/v3 v3.9.1 - github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 + github.com/patrickmn/go-cache v2.1.0+incompatible github.com/pborman/uuid v1.2.1 github.com/pkg/errors v0.9.1 github.com/psanford/memfs v0.0.0-20210214183328-a001468d78ef @@ -38,7 +37,6 @@ require ( go.opentelemetry.io/otel/sdk v1.13.0 go.opentelemetry.io/otel/trace v1.13.0 go.uber.org/fx v1.19.2 - gopkg.in/segmentio/analytics-go.v3 v3.1.0 gopkg.in/yaml.v3 v3.0.1 ) @@ -51,14 +49,12 @@ require ( github.com/ThreeDotsLabs/watermill-kafka/v2 v2.2.2 // indirect github.com/ThreeDotsLabs/watermill-nats/v2 v2.0.0 // indirect github.com/ajg/form v1.5.1 // indirect - github.com/bits-and-blooms/bloom v2.0.3+incompatible // indirect github.com/bytedance/sonic v1.8.1 // indirect github.com/cenkalti/backoff/v4 v4.2.0 // indirect github.com/cespare/xxhash/v2 v2.2.0 // indirect github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect github.com/containerd/continuity v0.3.0 // indirect github.com/davecgh/go-spew v1.1.1 // indirect - github.com/dgryski/go-metro v0.0.0-20200812162917-85c65e2d0165 // indirect github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect github.com/docker/cli v20.10.17+incompatible // indirect github.com/docker/docker v20.10.17+incompatible // indirect @@ -94,6 +90,7 @@ require ( github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/jackc/pgpassfile v1.0.0 // indirect github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a // indirect + github.com/jackc/puddle/v2 v2.2.1 // indirect github.com/jcmturner/aescts/v2 v2.0.0 // indirect github.com/jcmturner/dnsutils/v2 v2.0.0 // indirect github.com/jcmturner/gofork v1.7.6 // indirect @@ -117,14 +114,10 @@ require ( github.com/opencontainers/go-digest v1.0.0 // indirect github.com/opencontainers/image-spec v1.0.2 // indirect github.com/opencontainers/runc v1.1.3 // indirect - github.com/patrickmn/go-cache v2.1.0+incompatible // indirect github.com/pelletier/go-toml/v2 v2.0.6 // indirect github.com/pierrec/lz4/v4 v4.1.17 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 // indirect - github.com/segmentio/backo-go v1.0.1 // indirect - github.com/seiflotfy/cuckoofilter v0.0.0-20220411075957-e3b120b3f5fb // indirect - github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72 // indirect github.com/spf13/afero v1.9.3 // indirect github.com/spf13/cast v1.5.0 // indirect github.com/spf13/jwalterweatherman v1.1.0 // indirect @@ -134,14 +127,12 @@ require ( github.com/ugorji/go/codec v1.2.10 // indirect github.com/uptrace/opentelemetry-go-extra/otellogrus v0.1.21 // indirect github.com/uptrace/opentelemetry-go-extra/otelutil v0.1.21 // indirect - github.com/willf/bitset v1.1.11 // indirect github.com/xdg-go/pbkdf2 v1.0.0 // indirect github.com/xdg-go/scram v1.1.2 // indirect github.com/xdg-go/stringprep v1.0.4 // indirect github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect github.com/xeipuuv/gojsonschema v1.2.0 // indirect - github.com/xtgo/uuid v0.0.0-20140804021211-a0b114877d4c // indirect go.opentelemetry.io/contrib/instrumentation/github.com/Shopify/sarama/otelsarama v0.39.0 // indirect go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.39.0 // indirect go.opentelemetry.io/contrib/propagators/b3 v1.14.0 // indirect @@ -158,12 +149,13 @@ require ( go.uber.org/multierr v1.9.0 // indirect go.uber.org/zap v1.24.0 // indirect golang.org/x/arch v0.2.0 // indirect - golang.org/x/crypto v0.6.0 // indirect - golang.org/x/mod v0.7.0 // indirect - golang.org/x/net v0.7.0 // indirect - golang.org/x/sys v0.5.0 // indirect - golang.org/x/text v0.7.0 // indirect - golang.org/x/tools v0.5.0 // indirect + golang.org/x/crypto v0.17.0 // indirect + golang.org/x/mod v0.8.0 // indirect + golang.org/x/net v0.10.0 // indirect + golang.org/x/sync v0.1.0 // indirect + golang.org/x/sys v0.15.0 // indirect + golang.org/x/text v0.14.0 // indirect + golang.org/x/tools v0.6.0 // indirect google.golang.org/genproto v0.0.0-20230221151758-ace64dc21148 // indirect google.golang.org/grpc v1.53.0 // indirect google.golang.org/protobuf v1.28.1 // indirect diff --git a/go.sum b/go.sum index 99e98d414..0999ed060 100644 --- a/go.sum +++ b/go.sum @@ -43,8 +43,6 @@ github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym github.com/DATA-DOG/go-sqlmock v1.5.0 h1:Shsta01QNfFxHCfpW6YH2STWB0MudeXXEWMr20OEh60= github.com/DmitriyVTitov/size v1.5.0 h1:/PzqxYrOyOUX1BXj6J9OuVRVGe+66VL4D9FlUaW515g= github.com/DmitriyVTitov/size v1.5.0/go.mod h1:le6rNI4CoLQV1b9gzp1+3d7hMAD/uu2QcJ+aYbNgiU0= -github.com/Masterminds/semver/v3 v3.2.0 h1:3MEsd0SM6jqZojhjLWWeBY+Kcjy9i6MQAeY7YgDP83g= -github.com/Masterminds/semver/v3 v3.2.0/go.mod h1:qvl/7zhW3nngYb5+80sSMF+FG2BjYrf8m9wsX0PNOMQ= github.com/Microsoft/go-winio v0.6.0 h1:slsWYD/zyx7lCXoZVlvQrj0hPTM1HI4+v1sIda2yDvg= github.com/Microsoft/go-winio v0.6.0/go.mod h1:cTAf44im0RAYeL23bpB+fzCyDH2MJiz2BO69KH/soAE= github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 h1:TngWCqHvy9oXAN6lEVMRuU21PR1EtLVZJmdB18Gu3Rw= @@ -72,9 +70,6 @@ github.com/antlr/antlr4/runtime/Go/antlr v1.4.10/go.mod h1:F7bn7fEU90QkQ3tnmaTx3 github.com/benbjohnson/clock v1.3.0 h1:ip6w0uFQkncKQ979AypyG0ER7mqUSBdKLOgAle/AT8A= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= -github.com/bits-and-blooms/bloom v2.0.3+incompatible h1:3ONZFjJoMyfHDil5iCcNkcPJ//PNNo+55RHvPrfUGnY= -github.com/bits-and-blooms/bloom v2.0.3+incompatible/go.mod h1:nEmPH2pqJb3sCXfd7cyDSKC4iPfCAt312JHgNrtnnDE= -github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869 h1:DDGfHa7BWjL4YnC6+E63dPcxHo2sUxDIu8g3QgEJdRY= github.com/bool64/shared v0.1.5 h1:fp3eUhBsrSjNCQPcSdQqZxxh9bBwrYiZ+zOKFkM0/2E= github.com/buger/jsonparser v1.1.1 h1:2PnMjfWD7wBILjqQbt530v576A/cAbQvEW9gGIpYMUs= github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0= @@ -123,8 +118,6 @@ github.com/dgraph-io/ristretto v0.1.1 h1:6CWw5tJNgpegArSHpNHJKldNeq03FQCwYvfMVWa github.com/dgraph-io/ristretto v0.1.1/go.mod h1:S1GPSBCYCIhmVNfcth17y2zZtQT6wzkzgwUve0VDWWA= github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13 h1:fAjc9m62+UWV/WAFKLNi6ZS0675eEUC9y3AlwSbQu1Y= -github.com/dgryski/go-metro v0.0.0-20200812162917-85c65e2d0165 h1:BS21ZUJ/B5X2UVUbczfmdWH7GapPWAhxcMsDnjJTU1E= -github.com/dgryski/go-metro v0.0.0-20200812162917-85c65e2d0165/go.mod h1:c9O8+fpSOX1DM8cPNSkX/qsBWdkD4yd2dpciOWQjpBw= github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78= github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc= github.com/docker/cli v20.10.17+incompatible h1:eO2KS7ZFeov5UJeaDmIs1NFEDRf32PaqRpvoEkKBy5M= @@ -328,8 +321,10 @@ github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsI github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg= github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a h1:bbPeKD0xmW/Y25WS6cokEszi5g+S0QxI/d45PkRi7Nk= github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM= -github.com/jackc/pgx/v5 v5.3.0 h1:/NQi8KHMpKWHInxXesC8yD4DhkXPrVhmnwYkjp9AmBA= -github.com/jackc/pgx/v5 v5.3.0/go.mod h1:t3JDKnCBlYIc0ewLF0Q7B8MXmoIaBOZj/ic7iHozM/8= +github.com/jackc/pgx/v5 v5.5.5 h1:amBjrZVmksIdNjxGW/IiIMzxMKZFelXbUoPNb+8sjQw= +github.com/jackc/pgx/v5 v5.5.5/go.mod h1:ez9gk+OAat140fv9ErkZDYFWmXLfV+++K0uAOiwgm1A= +github.com/jackc/puddle/v2 v2.2.1 h1:RhxXJtFG022u4ibrCSMSiu5aOq1i77R3OHKNJj77OAk= +github.com/jackc/puddle/v2 v2.2.1/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4= github.com/jcmturner/aescts/v2 v2.0.0 h1:9YKLH6ey7H4eDBXW8khjYslgyqG2xZikXP0EQFKrle8= github.com/jcmturner/aescts/v2 v2.0.0/go.mod h1:AiaICIRyfYg35RUkr8yESTqvSy7csK90qZ5xfvvsoNs= github.com/jcmturner/dnsutils/v2 v2.0.0 h1:lltnkeZGL0wILNvrNiVCR6Ro5PGU/SeBvVO/8c/iPbo= @@ -431,8 +426,6 @@ github.com/ory/dockertest/v3 v3.9.1 h1:v4dkG+dlu76goxMiTT2j8zV7s4oPPEppKT8K8p2f1 github.com/ory/dockertest/v3 v3.9.1/go.mod h1:42Ir9hmvaAPm0Mgibk6mBPi7SFvTXxEcnztDYOJ//uM= github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc= github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ= -github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 h1:onHthvaw9LFnH4t2DcNVpwGmV9E1BkGknEliJkfwQj0= -github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58/go.mod h1:DXv8WO4yhMYhSNPKjeNKa5WY9YCIEBRbNzFFPJbWO6Y= github.com/pborman/uuid v1.2.1 h1:+ZZIw58t/ozdjRaXh/3awHfmWRbzYxJoAdNJxe/3pvw= github.com/pborman/uuid v1.2.1/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k= github.com/pelletier/go-toml/v2 v2.0.1/go.mod h1:r9LEWfGN8R5k0VXJ+0BkIe7MYkRdwZOjgMj2KwnJFUo= @@ -468,17 +461,12 @@ github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZV github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/seccomp/libseccomp-golang v0.9.2-0.20220502022130-f33da4d89646/go.mod h1:JA8cRccbGaA1s33RQf7Y1+q9gHmZX1yB/z9WDN1C6fg= -github.com/segmentio/backo-go v1.0.1 h1:68RQccglxZeyURy93ASB/2kc9QudzgIDexJ927N++y4= -github.com/segmentio/backo-go v1.0.1/go.mod h1:9/Rh6yILuLysoQnZ2oNooD2g7aBnvM7r/fNVxRNWfBc= -github.com/seiflotfy/cuckoofilter v0.0.0-20220411075957-e3b120b3f5fb h1:XfLJSPIOUX+osiMraVgIrMR27uMXnRJWGm1+GL8/63U= -github.com/seiflotfy/cuckoofilter v0.0.0-20220411075957-e3b120b3f5fb/go.mod h1:bR6DqgcAl1zTcOX8/pE2Qkj9XO00eCNqmKb7lXP8EAg= github.com/sergi/go-diff v1.3.1 h1:xkr+Oxo4BOQKmkn/B9eMK0g5Kg/983T9DqqPHwYqD+8= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0= github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= -github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72 h1:qLC7fQah7D6K1B0ujays3HV9gkFtllcxhzImRR7ArPQ= github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/spf13/afero v1.9.3 h1:41FoI0fD7OR7mGcKE/aOiLkGreyf8ifIOQmJANWogMk= github.com/spf13/afero v1.9.3/go.mod h1:iUV7ddyEEZPO5gA3zD4fJt6iStLlL+Lg4m2cihcDf8Y= @@ -525,8 +513,6 @@ github.com/uptrace/opentelemetry-go-extra/otelutil v0.1.21/go.mod h1:2MNqrUmDrt5 github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= github.com/vishvananda/netlink v1.1.0/go.mod h1:cTgwzPIzzgDAYoQrMm0EdrjRUBkTqKYppBueQtXaqoE= github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df/go.mod h1:JP3t17pCcGlemwknint6hfoeCVQrEMVwxRLRjXpq+BU= -github.com/willf/bitset v1.1.11 h1:N7Z7E9UvjW+sGsEl7k/SJrvY2reP1A07MrGuCjIOjRE= -github.com/willf/bitset v1.1.11/go.mod h1:83CECat5yLh5zVOf4P1ErAgKA5UDvKtgyUABdr3+MjI= github.com/xdg-go/pbkdf2 v1.0.0 h1:Su7DPu48wXMwC3bs7MCNG+z4FhcyEuz5dlvchbq0B0c= github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI= github.com/xdg-go/scram v1.1.2 h1:FHX5I5B4i4hKRVRBCFRxq1iQRej7WO3hhBuJf+UUySY= @@ -540,8 +526,6 @@ github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHo github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74= github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= -github.com/xtgo/uuid v0.0.0-20140804021211-a0b114877d4c h1:3lbZUMbMiGUW/LMkfsEABsc5zNT9+b1CvsJx47JzJ8g= -github.com/xtgo/uuid v0.0.0-20140804021211-a0b114877d4c/go.mod h1:UrdRz5enIKZ63MEE3IF9l2/ebyx59GyGgPi+tICQdmM= github.com/yudai/gojsondiff v1.0.0 h1:27cbfqXLVEJ1o8I6v3y9lg8Ydm53EKqHXAOMxEGlCOA= github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82 h1:BHyfKlQyqbsFN5p3IfnEUduWvb9is428/nNb5L3U01M= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= @@ -620,8 +604,8 @@ golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5y golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -golang.org/x/crypto v0.6.0 h1:qfktjS5LUO+fFKeJXZ+ikTRijMmljikvG68fpMMruSc= -golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= +golang.org/x/crypto v0.17.0 h1:r8bRNjWL3GshPW3gkd+RpvzWrZAwPS49OmTGZ/uhM4k= +golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -656,8 +640,8 @@ golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.1/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.7.0 h1:LapD9S96VoQRhi/GrNTqeBJFrUjs5UHCAtTlgwA5oZA= -golang.org/x/mod v0.7.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.8.0 h1:LUYupSeNrTNCGzR/hVBk2NHZO4hXcVaW1k4Qx7rjPx8= +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-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -697,8 +681,8 @@ golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96b 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.0.0-20220725212005-46097bf591d3/go.mod h1:AaygXjzTFtRAg2ttMY5RMuhpJ3cNnI0XpyFJD1iQRSM= -golang.org/x/net v0.7.0 h1:rJrUqqhjsgNp7KqAIc25s9pZnjU7TUcSY7HcVZjdn1g= -golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M= +golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -721,6 +705,7 @@ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/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 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o= +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-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -782,8 +767,8 @@ golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20221010170243-090e33056c14/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU= -golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc= +golang.org/x/sys v0.15.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/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -796,8 +781,8 @@ golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.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 h1:4BRB4x83lYWy72KwLD/qYDuTu7q9PjSagHvijDw7cLo= -golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= +golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -855,8 +840,8 @@ golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4f golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= -golang.org/x/tools v0.5.0 h1:+bSpV5HIeWkuvgaMfI3UmKRThoTA5ODJTUd8T17NO+4= -golang.org/x/tools v0.5.0/go.mod h1:N+Kgy78s5I24c24dU8OfWNEotWjutIs8SnJvn5IDq+k= +golang.org/x/tools v0.6.0 h1:BOw41kyTf3PuCW1pVQf8+Cyg8pMlkYB1oo9iJ6D/lKM= +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= @@ -974,8 +959,6 @@ gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= 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/segmentio/analytics-go.v3 v3.1.0 h1:UzxH1uaGZRpMKDhJyBz0pexz6yUoBU3x8bJsRk/HV6U= -gopkg.in/segmentio/analytics-go.v3 v3.1.0/go.mod h1:4QqqlTlSSpVlWA9/9nDcPw+FkM2yv1NQoYjUbL9/JAw= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= @@ -986,7 +969,6 @@ gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gopkg.in/yaml.v3 v3.0.0-20200605160147-a5ece683394c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= diff --git a/libs/analytics/cli.go b/libs/analytics/cli.go deleted file mode 100644 index b5d65543d..000000000 --- a/libs/analytics/cli.go +++ /dev/null @@ -1,67 +0,0 @@ -package analytics - -import ( - "time" - - "github.com/coreos/go-semver/semver" - "github.com/formancehq/stack/libs/go-libs/logging" - "github.com/spf13/cobra" - "github.com/spf13/viper" - "go.uber.org/fx" -) - -const ( - // deprecated - segmentEnabledFlag = "segment-enabled" - // deprecated - segmentWriteKeyFlag = "segment-write-flagKey" - // deprecated - segmentApplicationIdFlag = "segment-application-id" - // deprecated - segmentHeartbeatIntervalFlag = "segment-heartbeat-interval" - - telemetryEnabledFlag = "telemetry-enabled" - telemetryWriteKeyFlag = "telemetry-write-flagKey" - telemetryApplicationIdFlag = "telemetry-application-id" - telemetryHeartbeatIntervalFlag = "telemetry-heartbeat-interval" -) - -func InitAnalyticsFlags(cmd *cobra.Command, defaultWriteKey string, useDeprecatedFlags bool) { - if useDeprecatedFlags { - cmd.PersistentFlags().Bool(segmentEnabledFlag, false, "Is segment enabled") - cmd.PersistentFlags().String(segmentApplicationIdFlag, "", "Segment application id") - cmd.PersistentFlags().String(segmentWriteKeyFlag, defaultWriteKey, "Segment write flagKey") - cmd.PersistentFlags().Duration(segmentHeartbeatIntervalFlag, 4*time.Hour, "Segment heartbeat interval") - } - cmd.PersistentFlags().Bool(telemetryEnabledFlag, true, "Is telemetry enabled") - cmd.PersistentFlags().String(telemetryApplicationIdFlag, "", "telemetry application id") - cmd.PersistentFlags().String(telemetryWriteKeyFlag, defaultWriteKey, "telemetry write flagKey") - cmd.PersistentFlags().Duration(telemetryHeartbeatIntervalFlag, 4*time.Hour, "telemetry heartbeat interval") -} - -func NewAnalyticsModule(logger logging.Logger, v *viper.Viper, version string, useDeprecatedFlags bool) fx.Option { - if v.GetBool(telemetryEnabledFlag) || (useDeprecatedFlags && v.GetBool(segmentEnabledFlag)) { - - writeKey := viper.GetString(telemetryWriteKeyFlag) - if writeKey == "" && useDeprecatedFlags { - writeKey = viper.GetString(segmentWriteKeyFlag) - } - interval := viper.GetDuration(telemetryHeartbeatIntervalFlag) - if interval == 0 && useDeprecatedFlags { - interval = viper.GetDuration(segmentHeartbeatIntervalFlag) - } - if writeKey == "" { - logger.Infof("telemetry enabled but no write flagKey provided") - } else if interval == 0 { - logger.Error("telemetry heartbeat interval is 0") - } else { - _, err := semver.NewVersion(version) - if err != nil { - logger.Infof("telemetry enabled but version '%s' is not semver, skip", version) - } else { - return NewHeartbeatModule(version, writeKey, interval) - } - } - } - return fx.Options() -} diff --git a/libs/analytics/cli_test.go b/libs/analytics/cli_test.go deleted file mode 100644 index 742861898..000000000 --- a/libs/analytics/cli_test.go +++ /dev/null @@ -1,103 +0,0 @@ -package analytics - -import ( - "fmt" - "reflect" - "testing" - "time" - - "github.com/spf13/cobra" - "github.com/spf13/viper" - "github.com/stretchr/testify/require" -) - -func TestAnalyticsFlags(t *testing.T) { - type testCase struct { - name string - flagKey string - flagValue string - viperMethod interface{} - expectedValue interface{} - } - - for _, testCase := range []testCase{ - { - name: "using deprecated segment enabled flag", - flagKey: segmentEnabledFlag, - flagValue: "true", - viperMethod: (*viper.Viper).GetBool, - expectedValue: true, - }, - { - name: "using deprecated segment write flagKey flag", - flagKey: segmentWriteKeyFlag, - flagValue: "foo:bar", - viperMethod: (*viper.Viper).GetString, - expectedValue: "foo:bar", - }, - { - name: "using deprecated segment heartbeat interval flag", - flagKey: segmentHeartbeatIntervalFlag, - flagValue: "10s", - viperMethod: (*viper.Viper).GetDuration, - expectedValue: 10 * time.Second, - }, - { - name: "using deprecated segment application id flag", - flagKey: segmentApplicationIdFlag, - flagValue: "foo:bar", - viperMethod: (*viper.Viper).GetString, - expectedValue: "foo:bar", - }, - { - name: "using telemetry enabled flag", - flagKey: telemetryEnabledFlag, - flagValue: "true", - viperMethod: (*viper.Viper).GetBool, - expectedValue: true, - }, - { - name: "using telemetry write flagKey flag", - flagKey: telemetryWriteKeyFlag, - flagValue: "foo:bar", - viperMethod: (*viper.Viper).GetString, - expectedValue: "foo:bar", - }, - { - name: "using telemetry heartbeat interval flag", - flagKey: telemetryHeartbeatIntervalFlag, - flagValue: "10s", - viperMethod: (*viper.Viper).GetDuration, - expectedValue: 10 * time.Second, - }, - { - name: "using telemetry application id flag", - flagKey: telemetryApplicationIdFlag, - flagValue: "foo:bar", - viperMethod: (*viper.Viper).GetString, - expectedValue: "foo:bar", - }, - } { - t.Run(testCase.name, func(t *testing.T) { - v := viper.GetViper() - cmd := &cobra.Command{ - Run: func(cmd *cobra.Command, args []string) { - ret := reflect.ValueOf(testCase.viperMethod).Call([]reflect.Value{ - reflect.ValueOf(v), - reflect.ValueOf(testCase.flagKey), - }) - require.Len(t, ret, 1) - - rValue := ret[0].Interface() - require.Equal(t, testCase.expectedValue, rValue) - }, - } - InitAnalyticsFlags(cmd, "xxx", true) - - cmd.SetArgs([]string{fmt.Sprintf("--%s", testCase.flagKey), testCase.flagValue}) - - require.NoError(t, v.BindPFlags(cmd.PersistentFlags())) - require.NoError(t, cmd.Execute()) - }) - } -} diff --git a/libs/analytics/module.go b/libs/analytics/module.go deleted file mode 100644 index 055c42e9c..000000000 --- a/libs/analytics/module.go +++ /dev/null @@ -1,55 +0,0 @@ -package analytics - -import ( - "context" - "time" - - "github.com/google/uuid" - "github.com/segmentio/analytics-go" - "go.uber.org/fx" -) - -const ( - FXTagPropertiesEnrichers = `group:"enrichers"` -) - -func NewHeartbeatModule(version, writeKey string, interval time.Duration) fx.Option { - defaultAppId := uuid.NewString() - return fx.Options( - fx.Supply(analytics.Config{}), // Provide empty config to be able to replace (use fx.Replace) if necessary - fx.Provide(func(cfg analytics.Config) (analytics.Client, error) { - return analytics.NewWithConfig(writeKey, cfg) - }), - fx.Provide(fx.Annotate(func(client analytics.Client, provider AppIdProvider, enrichers []PropertiesEnricher) *heartbeat { - return newHeartbeat(provider, client, version, interval, enrichers...) - }, fx.ParamTags("", "", FXTagPropertiesEnrichers))), - fx.Provide(func() AppIdProvider { - return AppIdProviderFn(func(ctx context.Context) (string, error) { - return defaultAppId, nil - }) - }), - fx.Invoke(func(m *heartbeat, lc fx.Lifecycle) { - lc.Append(fx.Hook{ - OnStart: func(ctx context.Context) error { - go func() { - err := m.Run(context.Background()) - if err != nil { - panic(err) - } - }() - return nil - }, - OnStop: func(ctx context.Context) error { - return m.Stop(ctx) - }, - }) - }), - fx.Invoke(func(lc fx.Lifecycle, client analytics.Client) { - lc.Append(fx.Hook{ - OnStop: func(ctx context.Context) error { - return client.Close() - }, - }) - }), - ) -} diff --git a/libs/analytics/module_test.go b/libs/analytics/module_test.go deleted file mode 100644 index 998d59133..000000000 --- a/libs/analytics/module_test.go +++ /dev/null @@ -1,85 +0,0 @@ -package analytics - -import ( - "context" - "encoding/json" - "net/http" - "testing" - "time" - - "github.com/formancehq/stack/libs/go-libs/logging" - "github.com/segmentio/analytics-go" - "github.com/sirupsen/logrus" - "github.com/spf13/viper" - "github.com/stretchr/testify/require" - "go.uber.org/fx" -) - -type roundTripperFn func(req *http.Request) (*http.Response, error) - -func (fn roundTripperFn) RoundTrip(req *http.Request) (*http.Response, error) { - return fn(req) -} - -func TestAnalyticsModule(t *testing.T) { - v := viper.GetViper() - v.Set(telemetryEnabledFlag, true) - v.Set(telemetryWriteKeyFlag, "XXX") - v.Set(telemetryApplicationIdFlag, "appId") - v.Set(telemetryHeartbeatIntervalFlag, 10*time.Second) - - handled := make(chan *analytics.Track, 1) - - module := NewAnalyticsModule(logging.NewLogrus(logrus.New()), v, "1.0.0", true) - app := fx.New( - module, - fx.NopLogger, - fx.Supply(fx.Annotate(PropertiesEnricherFn(func(ctx context.Context, p analytics.Properties) error { - p.Set("additionalProperty", "test") - return nil - }), fx.As(new(PropertiesEnricher)), fx.ResultTags(FXTagPropertiesEnrichers))), - fx.Replace(analytics.Config{ - BatchSize: 1, - Transport: roundTripperFn(func(req *http.Request) (*http.Response, error) { - select { - case <-handled: - // Nothing to do, the chan has already been closed - default: - type batch struct { - Messages []*analytics.Track `json:"batch"` - } - b := batch{} - if err := json.NewDecoder(req.Body).Decode(&b); err != nil { - panic(err) - } - handled <- b.Messages[0] - close(handled) - } - return &http.Response{ - StatusCode: http.StatusOK, - }, nil - }), - })) - require.NoError(t, app.Start(context.Background())) - defer func() { - require.NoError(t, app.Stop(context.Background())) - }() - - select { - case <-time.After(time.Second): - require.Fail(t, "Timeout waiting first stats from analytics module") - case track := <-handled: - require.Equal(t, "test", track.Properties["additionalProperty"]) - } - -} - -func TestAnalyticsModuleDisabled(t *testing.T) { - v := viper.GetViper() - v.Set(telemetryEnabledFlag, false) - - module := NewAnalyticsModule(logging.NewLogrus(logrus.New()), v, "1.0.0", true) - app := fx.New(module, fx.NopLogger) - require.NoError(t, app.Start(context.Background())) - require.NoError(t, app.Stop(context.Background())) -} diff --git a/libs/analytics/segment.go b/libs/analytics/segment.go deleted file mode 100644 index f89389170..000000000 --- a/libs/analytics/segment.go +++ /dev/null @@ -1,126 +0,0 @@ -package analytics - -import ( - "context" - "runtime" - "time" - - "github.com/formancehq/stack/libs/go-libs/logging" - "github.com/pbnjay/memory" - "github.com/segmentio/analytics-go" -) - -const ( - ApplicationStats = "Application stats" - - VersionProperty = "version" - OSProperty = "os" - ArchProperty = "arch" - TimeZoneProperty = "tz" - CPUCountProperty = "cpuCount" - TotalMemoryProperty = "totalMemory" -) - -type AppIdProvider interface { - AppID(ctx context.Context) (string, error) -} -type AppIdProviderFn func(ctx context.Context) (string, error) - -func (fn AppIdProviderFn) AppID(ctx context.Context) (string, error) { - return fn(ctx) -} - -type PropertiesEnricher interface { - Enrich(ctx context.Context, p analytics.Properties) error -} -type PropertiesEnricherFn func(ctx context.Context, p analytics.Properties) error - -func (fn PropertiesEnricherFn) Enrich(ctx context.Context, p analytics.Properties) error { - return fn(ctx, p) -} - -type heartbeat struct { - version string - interval time.Duration - client analytics.Client - stopChan chan chan struct{} - appIdProvider AppIdProvider - enrichers []PropertiesEnricher -} - -func (m *heartbeat) Run(ctx context.Context) error { - - enqueue := func() { - err := m.enqueue(ctx) - if err != nil { - logging.FromContext(ctx).WithFields(map[string]interface{}{ - "error": err, - }).Error("enqueuing analytics") - } - } - - enqueue() - for { - select { - case ch := <-m.stopChan: - ch <- struct{}{} - return nil - case <-ctx.Done(): - return ctx.Err() - case <-time.After(m.interval): - enqueue() - } - } -} - -func (m *heartbeat) Stop(ctx context.Context) error { - ch := make(chan struct{}) - m.stopChan <- ch - select { - case <-ctx.Done(): - return ctx.Err() - case <-ch: - return nil - } -} - -func (m *heartbeat) enqueue(ctx context.Context) error { - - appId, err := m.appIdProvider.AppID(ctx) - if err != nil { - return err - } - - tz, _ := time.Now().Local().Zone() - - properties := analytics.NewProperties(). - Set(VersionProperty, m.version). - Set(OSProperty, runtime.GOOS). - Set(ArchProperty, runtime.GOARCH). - Set(TimeZoneProperty, tz). - Set(CPUCountProperty, runtime.NumCPU()). - Set(TotalMemoryProperty, memory.TotalMemory()/1024/1024) - - for _, enricher := range m.enrichers { - if err := enricher.Enrich(ctx, properties); err != nil { - logging.FromContext(ctx).Errorf("Enricher return error: %s", err) - } - } - - return m.client.Enqueue(&analytics.Track{ - AnonymousId: appId, - Event: ApplicationStats, - Properties: properties, - }) -} - -func newHeartbeat(appIdProvider AppIdProvider, client analytics.Client, version string, interval time.Duration, enrichers ...PropertiesEnricher) *heartbeat { - return &heartbeat{ - version: version, - interval: interval, - client: client, - appIdProvider: appIdProvider, - stopChan: make(chan chan struct{}, 1), - enrichers: enrichers, - } -} diff --git a/libs/analytics/segment_test.go b/libs/analytics/segment_test.go deleted file mode 100644 index ba53164ad..000000000 --- a/libs/analytics/segment_test.go +++ /dev/null @@ -1,166 +0,0 @@ -package analytics - -import ( - "bytes" - "context" - "encoding/json" - "errors" - "io" - "net/http" - "sync" - "testing" - "time" - - "github.com/segmentio/analytics-go" - "github.com/stretchr/testify/require" - "go.uber.org/fx" -) - -type transport func(*http.Request) (*http.Response, error) - -func (fn transport) RoundTrip(req *http.Request) (*http.Response, error) { - return fn(req) -} - -type Queue[ITEM any] struct { - mu sync.Mutex - items []ITEM -} - -func (s *Queue[ITEM]) Get() (ret ITEM, ok bool) { - s.mu.Lock() - defer s.mu.Unlock() - - if len(s.items) == 0 { - return - } - ret = s.items[0] - ok = true - if len(s.items) == 1 { - s.items = make([]ITEM, 0) - return - } - s.items = s.items[1:] - return -} - -func (s *Queue[ITEM]) Put(i ITEM) *Queue[ITEM] { - s.mu.Lock() - defer s.mu.Unlock() - - s.items = append(s.items, i) - return s -} - -func (s *Queue[ITEM]) Empty() bool { - s.mu.Lock() - defer s.mu.Unlock() - return len(s.items) == 0 -} - -func NewQueue[ITEM any]() *Queue[ITEM] { - return &Queue[ITEM]{} -} - -type segmentBatch struct { - Batch []analytics.Track `json:"batch"` -} - -const ( - interval = 10 * time.Millisecond - version = "100.0.0" - applicationId = "foo" - writeKey = "key" -) - -var ( - module = fx.Options( - fx.NopLogger, - NewHeartbeatModule(version, writeKey, interval), - fx.Replace(func() AppIdProvider { - return AppIdProviderFn(func(ctx context.Context) (string, error) { - return applicationId, nil - }) - }), - fx.Supply(fx.Annotate(PropertiesEnricherFn(func(ctx context.Context, p analytics.Properties) error { - p.Set("foo", "bar") - return nil - }), fx.ResultTags(FXTagPropertiesEnrichers), fx.As(new(PropertiesEnricher)))), - ) -) - -func EventuallyQueueNotEmpty[ITEM any](t *testing.T, queue *Queue[ITEM]) { - require.Eventually(t, func() bool { - return !queue.Empty() - }, 10*interval, interval) -} - -var emptyHttpResponse = &http.Response{ - Body: io.NopCloser(bytes.NewReader([]byte{})), - StatusCode: http.StatusOK, -} - -func newApp(module fx.Option, t transport) *fx.App { - return fx.New(module, fx.Replace(analytics.Config{ - BatchSize: 1, - Transport: t, - })) -} - -func withApp(t *testing.T, app *fx.App, fn func(t *testing.T)) { - require.NoError(t, app.Start(context.Background())) - defer func() { - require.NoError(t, app.Stop(context.Background())) - }() - fn(t) -} - -func TestSegment(t *testing.T) { - - t.Run("Nominal case", func(t *testing.T) { - queue := NewQueue[*http.Request]() - app := newApp(module, func(request *http.Request) (*http.Response, error) { - queue.Put(request) - return emptyHttpResponse, nil - }) - withApp(t, app, func(t *testing.T) { - for i := 0; i < 10; i++ { - EventuallyQueueNotEmpty(t, queue) - request, ok := queue.Get() - require.True(t, ok) - - username, password, ok := request.BasicAuth() - require.True(t, ok) - require.Equal(t, writeKey, username) - require.Empty(t, password) - - batch := &segmentBatch{} - require.NoError(t, json.NewDecoder(request.Body).Decode(batch)) - require.Len(t, batch.Batch, 1) - - track := batch.Batch[0] - require.Equal(t, ApplicationStats, track.Event) - require.Equal(t, "bar", track.Properties["foo"]) - } - }) - }) - t.Run("With error on the backend", func(t *testing.T) { - firstCall := true - - queue := NewQueue[*http.Request]() - app := newApp(module, func(request *http.Request) (*http.Response, error) { - if firstCall { - firstCall = false - return nil, errors.New("error on the first try") - } - queue.Put(request) - return emptyHttpResponse, nil - }) - withApp(t, app, func(t *testing.T) { - EventuallyQueueNotEmpty(t, queue) - - _, ok := queue.Get() - require.True(t, ok) - }) - }) -} diff --git a/pkg/analytics/segment.go b/pkg/analytics/segment.go deleted file mode 100644 index ddc78fc6e..000000000 --- a/pkg/analytics/segment.go +++ /dev/null @@ -1,215 +0,0 @@ -package analytics - -import ( - "context" - "crypto/sha256" - "encoding/base64" - "runtime" - "time" - - "github.com/formancehq/stack/libs/go-libs/logging" - "github.com/numary/ledger/pkg/ledger" - "github.com/numary/ledger/pkg/storage" - "github.com/pbnjay/memory" - "github.com/pborman/uuid" - "go.uber.org/fx" - "gopkg.in/segmentio/analytics-go.v3" -) - -const ( - ApplicationStats = "Application stats" - - VersionProperty = "version" - AccountsProperty = "accounts" - TransactionsProperty = "transactions" - LedgersProperty = "ledgers" - OSProperty = "os" - ArchProperty = "arch" - TimeZoneProperty = "tz" - CPUCountProperty = "cpuCount" - TotalMemoryProperty = "totalMemory" -) - -type AppIdProvider interface { - AppID(ctx context.Context) (string, error) -} -type AppIdProviderFn func(ctx context.Context) (string, error) - -func (fn AppIdProviderFn) AppID(ctx context.Context) (string, error) { - return fn(ctx) -} - -func FromStorageAppIdProvider(driver storage.Driver[ledger.Store]) AppIdProvider { - var appId string - return AppIdProviderFn(func(ctx context.Context) (string, error) { - var err error - if appId == "" { - appId, err = driver.GetSystemStore().GetConfiguration(ctx, "appId") - if err != nil && err != storage.ErrConfigurationNotFound { - return "", err - } - if err == storage.ErrConfigurationNotFound { - appId = uuid.New() - if err := driver.GetSystemStore().InsertConfiguration(ctx, "appId", appId); err != nil { - return "", err - } - } - } - return appId, nil - }) -} - -type heartbeat struct { - version string - interval time.Duration - client analytics.Client - stopChan chan chan struct{} - appIdProvider AppIdProvider - driver storage.Driver[ledger.Store] -} - -func (m *heartbeat) Run(ctx context.Context) error { - - enqueue := func() { - err := m.enqueue(ctx) - if err != nil { - logging.FromContext(ctx).WithFields(map[string]interface{}{ - "error": err, - }).Error("enqueuing analytics") - } - } - - enqueue() - for { - select { - case ch := <-m.stopChan: - ch <- struct{}{} - return nil - case <-ctx.Done(): - return ctx.Err() - case <-time.After(m.interval): - enqueue() - } - } -} - -func (m *heartbeat) Stop(ctx context.Context) error { - ch := make(chan struct{}) - m.stopChan <- ch - select { - case <-ctx.Done(): - return ctx.Err() - case <-ch: - return nil - } -} - -func (m *heartbeat) enqueue(ctx context.Context) error { - - appId, err := m.appIdProvider.AppID(ctx) - if err != nil { - return err - } - - tz, _ := time.Now().Local().Zone() - - properties := analytics.NewProperties(). - Set(VersionProperty, m.version). - Set(OSProperty, runtime.GOOS). - Set(ArchProperty, runtime.GOARCH). - Set(TimeZoneProperty, tz). - Set(CPUCountProperty, runtime.NumCPU()). - Set(TotalMemoryProperty, memory.TotalMemory()/1024/1024) - - ledgers, err := m.driver.GetSystemStore().ListLedgers(ctx) - if err != nil { - return err - } - - ledgersProperty := map[string]any{} - - for _, l := range ledgers { - stats := map[string]any{} - if err := func() error { - store, _, err := m.driver.GetLedgerStore(ctx, l, false) - if err != nil { - return err - } - transactions, err := store.CountTransactions(ctx, ledger.TransactionsQuery{}) - if err != nil { - return err - } - accounts, err := store.CountAccounts(ctx, ledger.AccountsQuery{}) - if err != nil { - return err - } - stats[TransactionsProperty] = transactions - stats[AccountsProperty] = accounts - - return nil - }(); err != nil { - return err - } - - digest := sha256.New() - digest.Write([]byte(l)) - ledgerHash := base64.RawURLEncoding.EncodeToString(digest.Sum(nil)) - - ledgersProperty[ledgerHash] = stats - } - if len(ledgersProperty) > 0 { - properties.Set(LedgersProperty, ledgersProperty) - } - - return m.client.Enqueue(&analytics.Track{ - AnonymousId: appId, - Event: ApplicationStats, - Properties: properties, - }) -} - -func newHeartbeat(appIdProvider AppIdProvider, driver storage.Driver[ledger.Store], client analytics.Client, version string, interval time.Duration) *heartbeat { - return &heartbeat{ - version: version, - interval: interval, - client: client, - driver: driver, - appIdProvider: appIdProvider, - stopChan: make(chan chan struct{}, 1), - } -} - -func NewHeartbeatModule(version, writeKey string, interval time.Duration) fx.Option { - return fx.Options( - fx.Supply(analytics.Config{}), // Provide empty config to be able to replace (use fx.Replace) if necessary - fx.Provide(func(cfg analytics.Config) (analytics.Client, error) { - return analytics.NewWithConfig(writeKey, cfg) - }), - fx.Provide(func(client analytics.Client, provider AppIdProvider, driver storage.Driver[ledger.Store]) *heartbeat { - return newHeartbeat(provider, driver, client, version, interval) - }), - fx.Invoke(func(m *heartbeat, lc fx.Lifecycle) { - lc.Append(fx.Hook{ - OnStart: func(ctx context.Context) error { - go func() { - err := m.Run(context.Background()) - if err != nil { - panic(err) - } - }() - return nil - }, - OnStop: func(ctx context.Context) error { - return m.Stop(ctx) - }, - }) - }), - fx.Invoke(func(lc fx.Lifecycle, client analytics.Client) { - lc.Append(fx.Hook{ - OnStop: func(ctx context.Context) error { - return client.Close() - }, - }) - }), - ) -} diff --git a/pkg/analytics/segment_test.go b/pkg/analytics/segment_test.go deleted file mode 100644 index 66a8c8ac7..000000000 --- a/pkg/analytics/segment_test.go +++ /dev/null @@ -1,177 +0,0 @@ -package analytics - -import ( - "bytes" - "context" - "encoding/json" - "errors" - "io" - "net/http" - "os" - "sync" - "testing" - "time" - - "github.com/numary/ledger/pkg/ledger" - "github.com/numary/ledger/pkg/storage" - "github.com/numary/ledger/pkg/storage/sqlstorage" - "github.com/pborman/uuid" - "github.com/stretchr/testify/require" - "go.uber.org/fx" - "gopkg.in/segmentio/analytics-go.v3" -) - -type transport func(*http.Request) (*http.Response, error) - -func (fn transport) RoundTrip(req *http.Request) (*http.Response, error) { - return fn(req) -} - -type Queue[ITEM any] struct { - mu sync.Mutex - items []ITEM -} - -func (s *Queue[ITEM]) Get() (ret ITEM, ok bool) { - s.mu.Lock() - defer s.mu.Unlock() - - if len(s.items) == 0 { - return - } - ret = s.items[0] - ok = true - if len(s.items) == 1 { - s.items = make([]ITEM, 0) - return - } - s.items = s.items[1:] - return -} - -func (s *Queue[ITEM]) Put(i ITEM) *Queue[ITEM] { - s.mu.Lock() - defer s.mu.Unlock() - - s.items = append(s.items, i) - return s -} - -func (s *Queue[ITEM]) Empty() bool { - s.mu.Lock() - defer s.mu.Unlock() - return len(s.items) == 0 -} - -func NewQueue[ITEM any]() *Queue[ITEM] { - return &Queue[ITEM]{} -} - -type segmentBatch struct { - Batch []analytics.Track `json:"batch"` -} - -const ( - interval = 10 * time.Millisecond - version = "100.0.0" - applicationId = "foo" - writeKey = "key" -) - -var ( - module = fx.Options( - NewHeartbeatModule(version, writeKey, interval), - fx.Provide(func() AppIdProvider { - return AppIdProviderFn(func(ctx context.Context) (string, error) { - return "foo", nil - }) - }), - fx.Provide(func(lc fx.Lifecycle) (storage.Driver[ledger.Store], error) { - id := uuid.New() - driver := sqlstorage.NewDriver("sqlite", sqlstorage.NewSQLiteDB(os.TempDir(), id), false) - lc.Append(fx.Hook{ - OnStart: driver.Initialize, - }) - return sqlstorage.NewLedgerStorageDriverFromRawDriver(driver), nil - }), - ) -) - -func EventuallyQueueNotEmpty[ITEM any](t *testing.T, queue *Queue[ITEM]) { - require.Eventually(t, func() bool { - return !queue.Empty() - }, 10*interval, interval) -} - -var emptyHttpResponse = &http.Response{ - Body: io.NopCloser(bytes.NewReader([]byte{})), - StatusCode: http.StatusOK, -} - -func newApp(module fx.Option, t transport) *fx.App { - return fx.New(module, fx.Replace(analytics.Config{ - BatchSize: 1, - Transport: t, - })) -} - -func withApp(t *testing.T, app *fx.App, fn func(t *testing.T)) { - require.NoError(t, app.Start(context.Background())) - defer func() { - require.NoError(t, app.Stop(context.Background())) - }() - fn(t) -} - -func TestSegment(t *testing.T) { - - t.Run("Nominal case", func(t *testing.T) { - queue := NewQueue[*http.Request]() - app := newApp(module, func(request *http.Request) (*http.Response, error) { - queue.Put(request) - return emptyHttpResponse, nil - }) - withApp(t, app, func(t *testing.T) { - for i := 0; i < 10; i++ { - EventuallyQueueNotEmpty(t, queue) - request, ok := queue.Get() - require.True(t, ok) - - username, password, ok := request.BasicAuth() - require.True(t, ok) - require.Equal(t, writeKey, username) - require.Empty(t, password) - - batch := &segmentBatch{} - require.NoError(t, json.NewDecoder(request.Body).Decode(batch)) - require.Len(t, batch.Batch, 1) - - track := batch.Batch[0] - require.Equal(t, ApplicationStats, track.Event) - require.Equal(t, version, track.Properties[VersionProperty]) - require.Equal(t, applicationId, track.AnonymousId) - } - }) - }) - t.Run("With error on the backend", func(t *testing.T) { - firstCallChan := make(chan struct{}) - - queue := NewQueue[*http.Request]() - app := newApp(module, func(request *http.Request) (*http.Response, error) { - select { - case <-firstCallChan: // Enter this case only if the chan is closed - queue.Put(request) - return emptyHttpResponse, nil - default: - close(firstCallChan) - return nil, errors.New("general error") - } - }) - withApp(t, app, func(t *testing.T) { - EventuallyQueueNotEmpty(t, queue) - - _, ok := queue.Get() - require.True(t, ok) - }) - }) -}