diff --git a/.github/workflows/golangci-lint.yml b/.github/workflows/golangci-lint.yml index a3b265d..34c9ed4 100644 --- a/.github/workflows/golangci-lint.yml +++ b/.github/workflows/golangci-lint.yml @@ -24,25 +24,6 @@ jobs: go-version: stable - uses: actions/checkout@v4 - name: golangci-lint - uses: golangci/golangci-lint-action@v6.5.0 + uses: golangci/golangci-lint-action@v9.2.0 with: - # Required: the version of golangci-lint is required and must be specified without patch version: we always use the latest patch version. - version: v1.64.5 - - # Optional: working directory, useful for monorepos - # working-directory: somedir - - # Optional: golangci-lint command line arguments. - # args: --issues-exit-code=0 - - # Optional: show only new issues if it's a pull request. The default value is `false`. - # only-new-issues: true - - # Optional: if set to true then the action will use pre-installed Go. - # skip-go-installation: true - - # Optional: if set to true then the action don't cache or restore ~/go/pkg. - # skip-pkg-cache: true - - # Optional: if set to true then the action don't cache or restore ~/.cache/go-build. - # skip-build-cache: true \ No newline at end of file + version: v2.11.3 diff --git a/.github/workflows/test-unit.yml b/.github/workflows/test-unit.yml index a91bfee..978f679 100644 --- a/.github/workflows/test-unit.yml +++ b/.github/workflows/test-unit.yml @@ -80,8 +80,9 @@ jobs: curl -sLO https://github.com/vearutop/gocovdiff/releases/download/v1.4.2/linux_amd64.tar.gz && tar xf linux_amd64.tar.gz && rm linux_amd64.tar.gz gocovdiff_hash=$(git hash-object ./gocovdiff) [ "$gocovdiff_hash" == "c37862c73a677e5a9c069470287823ab5bbf0244" ] || (echo "::error::unexpected hash for gocovdiff, possible tampering: $gocovdiff_hash" && exit 1) - git fetch origin master ${{ github.event.pull_request.base.sha }} - REP=$(./gocovdiff -mod github.com/$GITHUB_REPOSITORY -cov unit.coverprofile -gha-annotations gha-unit.txt -delta-cov-file delta-cov-unit.txt -target-delta-cov ${TARGET_DELTA_COV}) + # Fetch PR diff from GitHub API. + curl -s -H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" -H "Accept: application/vnd.github.v3.diff" https://api.github.com/repos/${{ github.repository }}/pulls/${{ github.event.pull_request.number }} > pull_request.diff + REP=$(./gocovdiff -diff pull_request.diff -mod github.com/$GITHUB_REPOSITORY -cov unit.coverprofile -gha-annotations gha-unit.txt -delta-cov-file delta-cov-unit.txt -target-delta-cov ${TARGET_DELTA_COV}) echo "${REP}" cat gha-unit.txt DIFF=$(test -e unit-base.txt && ./gocovdiff -mod github.com/$GITHUB_REPOSITORY -func-cov unit.txt -func-base-cov unit-base.txt || echo "Missing base coverage file") diff --git a/.gitignore b/.gitignore index 513a049..5acda26 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,4 @@ /.vscode /bench-*.txt /vendor +/_refs diff --git a/.golangci.yml b/.golangci.yml index ffd001b..a86614e 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -1,67 +1,83 @@ -# See https://github.com/golangci/golangci-lint/blob/master/.golangci.example.yml +# See https://golangci-lint.run/docs/linters/configuration/ +version: "2" run: tests: true - -linters-settings: - errcheck: - check-type-assertions: true - check-blank: true - gocyclo: - min-complexity: 20 - dupl: - threshold: 100 - misspell: - locale: US - unparam: - check-exported: true - funlen: - lines: 70 - linters: - enable-all: true + default: all disable: - - intrange + - embeddedstructfieldcheck + - nilnil + - noinlineerr + - wsl_v5 + - funcorder - copyloopvar - - lll - - gochecknoglobals - - wrapcheck - - paralleltest + - depguard + - dupword + - errname + - exhaustruct - forbidigo - forcetypeassert - - varnamelen - - tagliatelle - - errname + - gochecknoglobals + - intrange - ireturn - - exhaustruct + - lll + - mnd - nonamedreturns - - testableexamples - - dupword - - depguard + - paralleltest + - recvcheck - tagalign - - mnd + - tagliatelle + - testableexamples - testifylint - - recvcheck - -issues: - exclude-use-default: false - exclude-rules: - - linters: - - gosec - text: 'G115: integer overflow conversion' - - linters: - - mnd - - goconst - - noctx - - funlen - - dupl - - unused - - unparam - path: "_test.go" - - linters: - - errcheck # Error checking omitted for brevity. - - gosec - path: "example_" - - linters: - - revive - text: "unused-parameter: parameter" - + - varnamelen + - wrapcheck + settings: + dupl: + threshold: 100 + errcheck: + check-type-assertions: true + check-blank: true + gocyclo: + min-complexity: 20 + misspell: + locale: US + unparam: + check-exported: true + cyclop: + max-complexity: 15 + exclusions: + generated: lax + rules: + - linters: + - gosec + - dupl + - funlen + - goconst + - mnd + - noctx + - unparam + - unused + path: _test.go + - linters: + - errcheck + - gosec + path: example_ + - linters: + - revive + text: 'unused-parameter: parameter' + paths: + - third_party$ + - builtin$ + - examples$ +formatters: + enable: + - gci + - gofmt + - gofumpt + - goimports + exclusions: + generated: lax + paths: + - third_party$ + - builtin$ + - examples$ diff --git a/Makefile b/Makefile index 8b4c583..47a73ec 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -#GOLANGCI_LINT_VERSION := "v1.64.5" # Optional configuration to pinpoint golangci-lint version. +#GOLANGCI_LINT_VERSION := "v2.11.3" # Optional configuration to pinpoint golangci-lint version. # The head of Makefile determines location of dev-go to include standard targets. GO ?= go diff --git a/cache.go b/cache.go index 73fa473..2d854eb 100644 --- a/cache.go +++ b/cache.go @@ -36,7 +36,7 @@ func MakeCacheOf[V any](l interface { } if cfg.Backend == nil { - cfg.Backend = cache.NewShardedMapOf[V](func(cfg *cache.Config) { + cfg.Backend = cache.NewShardedMapOf[V](func(cfg *cache.ConfigOf[V]) { cfg.Name = name cfg.Logger = l.CtxdLogger() cfg.Stats = l.StatsTracker() @@ -66,3 +66,50 @@ func MakeCacheOf[V any](l interface { return fc } + +// MakeCacheBy creates an instance of failover cache and adds it to cache transfer. +func MakeCacheBy[K comparable, V any](l interface { + StatsTracker() stats.Tracker + CtxdLogger() ctxd.Logger +}, name string, ttl time.Duration, options ...func(cfg *cache.FailoverConfigBy[K, V]), +) *cache.FailoverBy[K, V] { + cfg := cache.FailoverConfigBy[K, V]{} + cfg.Name = name + cfg.Stats = l.StatsTracker() + cfg.Logger = l.CtxdLogger() + + for _, option := range options { + option(&cfg) + } + + if cfg.Backend == nil { + cfg.Backend = cache.NewShardedMapBy[K, V](func(cfg *cache.ConfigBy[K, V]) { + cfg.Name = name + cfg.Logger = l.CtxdLogger() + cfg.Stats = l.StatsTracker() + cfg.TimeToLive = ttl + }) + } + + fc := cache.NewFailoverBy[K, V](func(c *cache.FailoverConfigBy[K, V]) { + *c = cfg + }) + + if l, ok := l.(interface { + CacheTransfer() *cache.HTTPTransfer + }); ok { + if w, ok := cfg.Backend.(cache.WalkDumpRestorer); ok { + l.CacheTransfer().AddCache(name, w) + } + } + + if l, ok := l.(interface { + CacheInvalidationIndex() *cache.InvalidationIndex + }); ok { + if d, ok := cfg.Backend.(cache.Deleter); ok { + l.CacheInvalidationIndex().AddCache(name, d) + } + } + + return fc +} diff --git a/cmd.go b/cmd.go index e308a67..a99de77 100644 --- a/cmd.go +++ b/cmd.go @@ -30,7 +30,7 @@ type StartOptions struct { } // Start loads config and runs application with provided service locator and http router. -func Start(cfg WithBaseConfig, init func(docsMode bool) (*BaseLocator, http.Handler), options ...func(o *StartOptions)) { //nolint:cyclop +func Start(cfg WithBaseConfig, init func(docsMode bool) (*BaseLocator, http.Handler), options ...func(o *StartOptions)) { ver := flag.Bool("version", false, "Print application version and exit.") docs := flag.Bool("openapi", false, "Print application OpenAPI spec and exit.") confFile := flag.String("conf", "", "Config file with ENV variables to load.") diff --git a/config.go b/config.go index 5fa986f..6c18486 100644 --- a/config.go +++ b/config.go @@ -4,6 +4,7 @@ import ( "time" "github.com/bool64/brick/debug" + "github.com/bool64/brick/telemetry" "github.com/bool64/zapctxd" ) @@ -29,6 +30,9 @@ type BaseConfig struct { // Debug controls dev tools. Debug debug.Config `split_words:"true"` + // Telemetry configures OpenTelemetry export. + Telemetry telemetry.Config `split_words:"true"` + // CacheTransferURL is URL to fetch cache from on application start. CacheTransferURL string `split_words:"true"` } diff --git a/config/config.go b/config/config.go index 1d9e15b..897f826 100644 --- a/config/config.go +++ b/config/config.go @@ -71,7 +71,7 @@ func DefaultLoaders(prefix string) []func() error { // // In no loaders are provided then vars from .env.template, .env, .env. // files are loaded if available. Use nil or any other source to avoid that. -func Load(prefix string, spec interface{}, loaders ...func() error) error { +func Load(prefix string, spec any, loaders ...func() error) error { if len(loaders) == 0 { loaders = DefaultLoaders(prefix) } @@ -94,7 +94,7 @@ func Load(prefix string, spec interface{}, loaders ...func() error) error { return validate(spec) } -func validate(spec interface{}) error { +func validate(spec any) error { specj, err := json.Marshal(spec) if err != nil { return fmt.Errorf("json marshal: %w", err) diff --git a/config/config_test.go b/config/config_test.go index 5d3864b..fb8d421 100644 --- a/config/config_test.go +++ b/config/config_test.go @@ -1,20 +1,14 @@ package config_test import ( - "os" "testing" "github.com/bool64/brick/config" "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" ) func TestLoad(t *testing.T) { - require.NoError(t, os.Chdir("./__testdata")) - - defer func() { - require.NoError(t, os.Chdir("..")) - }() + t.Chdir("./__testdata") cfg := struct { Foo string diff --git a/database/observability.go b/database/observability.go index a5f04a1..c9f92c3 100644 --- a/database/observability.go +++ b/database/observability.go @@ -7,30 +7,25 @@ import ( "fmt" "time" - "contrib.go.opencensus.io/integrations/ocsql" + "github.com/XSAM/otelsql" "github.com/bool64/ctxd" "github.com/bool64/dbwrap" "github.com/bool64/stats" - "go.opencensus.io/trace" + "go.opentelemetry.io/otel" + "go.opentelemetry.io/otel/attribute" + "go.opentelemetry.io/otel/codes" ) -// withTracing instruments database connector with OpenCensus tracing. -func withTracing(dbConnector driver.Connector) driver.Connector { - return ocsql.WrapConnector(dbConnector, tracingOptions()...) -} - -// driverNameWithTracing registers database driver name with OpenCensus tracing. +// driverNameWithTracing registers database driver name with OpenTelemetry instrumentation. func driverNameWithTracing(driverName string) (string, error) { - return ocsql.Register(driverName, tracingOptions()...) + return otelsql.Register(driverName, tracingOptions()...) } -func tracingOptions() []ocsql.TraceOption { - return []ocsql.TraceOption{ - ocsql.WithQuery(true), - ocsql.WithRowsClose(true), - ocsql.WithRowsAffected(true), - ocsql.WithAllowRoot(true), - ocsql.WithDisableErrSkip(true), +func tracingOptions() []otelsql.Option { + return []otelsql.Option{ + otelsql.WithTracerProvider(otel.GetTracerProvider()), + otelsql.WithMeterProvider(otel.GetMeterProvider()), + otelsql.WithDisableSkipErrMeasurement(true), } } @@ -93,10 +88,10 @@ func observe(logger ctxd.Logger, statsTracker stats.Tracker, skipPackages []stri return nil, nil } - ctx, span := trace.StartSpan(ctx, caller+":"+string(operation)) - span.AddAttributes( - trace.StringAttribute("stmt", statement), - trace.StringAttribute("args", fmt.Sprintf("%v", args)), + ctx, span := otel.Tracer("github.com/bool64/brick/database").Start(ctx, caller+":"+string(operation)) + span.SetAttributes( + attribute.String("db.statement", statement), + attribute.String("db.args", fmt.Sprintf("%v", args)), ) statsTracker.Add(ctx, "sql_storage_queries_total", 1, "method", caller) @@ -114,7 +109,8 @@ func observe(logger ctxd.Logger, statsTracker stats.Tracker, skipPackages []stri res := " complete" if err != nil { - span.SetStatus(trace.Status{Message: err.Error()}) + span.SetStatus(codes.Error, err.Error()) + span.RecordError(err) res = " failed" } diff --git a/database/storage.go b/database/storage.go index 40abf50..8eeb612 100644 --- a/database/storage.go +++ b/database/storage.go @@ -10,6 +10,7 @@ import ( "strings" "github.com/Masterminds/squirrel" + "github.com/XSAM/otelsql" "github.com/bool64/ctxd" "github.com/bool64/sqluct" "github.com/bool64/stats" @@ -20,10 +21,9 @@ import ( // SetupStorage initializes database pool and prepares storage. func SetupStorage(cfg Config, logger ctxd.Logger, statsTracker stats.Tracker, conn driver.Connector, migrations fs.FS) (*sqluct.Storage, error) { - conn = withTracing(conn) conn = withQueriesLogging(cfg, conn, logger, statsTracker) - db := sql.OpenDB(conn) + db := otelsql.OpenDB(conn, tracingOptions()...) return setupStorage(cfg, db, migrations, logger) } @@ -53,6 +53,11 @@ func setupStorage(cfg Config, db *sql.DB, migrations fs.FS, logger ctxd.Logger) db.SetMaxOpenConns(cfg.MaxOpen) db.SetConnMaxLifetime(cfg.MaxLifetime) + // Export database/sql pool stats alongside query traces and operation metrics. + if _, err := otelsql.RegisterDBStatsMetrics(db, tracingOptions()...); err != nil { + return nil, fmt.Errorf("register db stats metrics: %w", err) + } + st := sqluct.NewStorage(sqlx.NewDb(db, cfg.DriverName)) st.Mapper = &sqluct.Mapper{} dialect := cfg.DriverName @@ -74,7 +79,7 @@ func setupStorage(cfg Config, db *sql.DB, migrations fs.FS, logger ctxd.Logger) } if cfg.InitConn { - if err := db.Ping(); err != nil { + if err := db.PingContext(context.Background()); err != nil { return nil, fmt.Errorf("ping database: %w", err) } } @@ -103,16 +108,16 @@ type gooseLogger struct { l ctxd.Logger } -func (l gooseLogger) Fatal(v ...interface{}) { l.l.Error(l.c, fmt.Sprint(v...)); os.Exit(1) } -func (l gooseLogger) Fatalf(f string, v ...interface{}) { +func (l gooseLogger) Fatal(v ...any) { l.l.Error(l.c, fmt.Sprint(v...)); os.Exit(1) } +func (l gooseLogger) Fatalf(f string, v ...any) { l.l.Error(l.c, fmt.Sprintf(f, v...)) os.Exit(1) } -func (l gooseLogger) Print(v ...interface{}) { +func (l gooseLogger) Print(v ...any) { l.l.Info(l.c, strings.TrimRight(fmt.Sprint(v...), "\n")) } -func (l gooseLogger) Println(v ...interface{}) { l.l.Info(l.c, fmt.Sprint(v...)) } -func (l gooseLogger) Printf(f string, v ...interface{}) { +func (l gooseLogger) Println(v ...any) { l.l.Info(l.c, fmt.Sprint(v...)) } +func (l gooseLogger) Printf(f string, v ...any) { l.l.Info(l.c, strings.TrimRight(fmt.Sprintf(f, v...), "\n")) } diff --git a/debug.go b/debug.go index 5010147..055a2cc 100644 --- a/debug.go +++ b/debug.go @@ -6,6 +6,7 @@ import ( "github.com/bool64/brick/debug" "github.com/bool64/brick/debug/zpages" + "github.com/bool64/brick/telemetry" "github.com/bool64/dev/version" "github.com/bool64/logz/ctxz" "github.com/bool64/logz/logzpage" @@ -14,6 +15,7 @@ import ( "github.com/go-chi/chi/v5/middleware" "github.com/prometheus/client_golang/prometheus/promhttp" swg "github.com/swaggest/swgui/v5cdn" + otelzpages "go.opentelemetry.io/contrib/zpages" ) // MountDevPortal mounts debug handlers to router. @@ -40,6 +42,10 @@ func (l *BaseLocator) SetupDebugRouter() { return } + l.DebugRouter = newDebugRouter(l, nil) +} + +func newDebugRouter(l *BaseLocator, tracezProcessor *otelzpages.SpanProcessor) *debug.Mux { cfg := l.BaseConfig prefix := cfg.Debug.URL @@ -50,17 +56,19 @@ func (l *BaseLocator) SetupDebugRouter() { dr.AddLink("zpages/tracez", "Trace Spans") - if cfg.Debug.TraceURL != "" { - dr.Mount("/zpages", zpages.Mux(prefix+"/zpages", func(traceID string) string { - return strings.ReplaceAll(cfg.Debug.TraceURL, "{trace_id}", traceID) - })) - } else { - dr.Mount("/zpages", zpages.Mux(prefix+"/zpages", nil)) + if tracezProcessor != nil { + if cfg.Debug.TraceURL != "" { + dr.Mount("/zpages", zpages.Mux(prefix+"/zpages", tracezProcessor, func(traceID string) string { + return strings.ReplaceAll(cfg.Debug.TraceURL, "{trace_id}", traceID) + })) + } else { + dr.Mount("/zpages", zpages.Mux(prefix+"/zpages", tracezProcessor, nil)) + } } if pt, ok := l.StatsTracker().(*prom.Tracker); ok { dr.AddLink("metrics", "Metrics") - dr.Method(http.MethodGet, "/metrics", promhttp.HandlerFor(pt.PrometheusRegistry(), promhttp.HandlerOpts{})) + dr.Method(http.MethodGet, "/metrics", promhttp.HandlerFor(telemetry.PrometheusGatherer(pt.PrometheusRegistry()), promhttp.HandlerOpts{})) } if lz, ok := l.CtxdLogger().(ctxz.Observer); ok { @@ -80,5 +88,5 @@ func (l *BaseLocator) SetupDebugRouter() { dr.Mount("/docs", swg.NewHandler(l.OpenAPI.Reflector().SpecEns().Info.Title, prefix+"/docs/openapi.json", prefix+"/docs")) - l.DebugRouter = dr + return dr } diff --git a/debug/config.go b/debug/config.go index e0a0673..1c6bb82 100644 --- a/debug/config.go +++ b/debug/config.go @@ -8,7 +8,7 @@ import ( // Config keeps debug settings. type Config struct { - // TraceSamplingProbability is probability of exporting of OpenCensus trace. + // TraceSamplingProbability is probability of sampling OpenTelemetry traces. TraceSamplingProbability float64 `split_words:"true" default:"0.1"` // TraceURL allows providing URL to {trace_id}, example http://jaeger.myservice.com/trace/{trace_id}. @@ -27,7 +27,7 @@ type Config struct { // can be useful for non-production environments. ExposePanic bool `split_words:"true"` - OnPanic []func(ctx context.Context, rcv interface{}, stack []byte) `json:"-" ignored:"true"` + OnPanic []func(ctx context.Context, rcv any, stack []byte) `json:"-" ignored:"true"` Middlewares chi.Middlewares `envconfig:"-" json:"-"` } diff --git a/debug/zpages/mux.go b/debug/zpages/mux.go index feab2ad..4fee1d9 100644 --- a/debug/zpages/mux.go +++ b/debug/zpages/mux.go @@ -1,111 +1,17 @@ -// Package zpages provides OpenCensus zpages handlers. +// Package zpages provides OpenTelemetry tracez handlers. package zpages import ( - "bytes" - "html" "net/http" - "net/http/httptest" - "regexp" - "go.opencensus.io/zpages" + otelzpages "go.opentelemetry.io/contrib/zpages" ) -const css = ` -body{font-family: 'Roboto',sans-serif; -font-size: 14px;background-color: #F2F4EC;} -h1{color: #3D3D3D;text-align: center;margin-bottom: 20px;} -p{padding: 0 0.5em;color: #3D3D3D;} -h2{color: #3D3D3D;font-size: 1.5em;background-color: #FFF; -line-height: 2.0;margin-bottom: 0;padding: 0 0.5em;} -h3{font-size:16px;padding:0 0.5em;margin-top:6px;margin-bottom:25px;} -a{color:#A94442;} -p.header{font-family: 'Open Sans', sans-serif;top: 0;left: 0;width: 100%; -height: 60px;vertical-align: middle;color: #C1272D;font-size: 22pt;} -p.view{font-size: 20px;margin-bottom: 0;} -.header span{color: #3D3D3D;} -img.oc{vertical-align: middle;} -table{width: 100%;color: #FFF;background-color: #FFF;overflow: hidden; -margin-bottom: 30px;margin-top: 0;border-bottom: 1px solid #3D3D3D; -border-left: 1px solid #3D3D3D;border-right: 1px solid #3D3D3D;} -table.title{width:100%;color:#3D3D3D;background-color:#FFF; -border:none;line-height:2.0;margin-bottom:0;} -thead{color: #FFF;background-color: #A94442; -line-height:3.0;padding:0 0.5em;} -th{color: #FFF;background-color: #A94442; -line-height:3.0;padding:0 0.5em;} -th.borderL{border-left:1px solid #FFF; text-align:left;} -th.borderRL{border-right:1px solid #FFF; text-align:left;} -th.borderLB{border-left:1px solid #FFF; -border-bottom:1px solid #FFF;margin:0 10px;} -tr.direct{font-size:16px;padding:0 0.5em;background-color:#F2F4EC;} -tr:nth-child(even){background-color: #F2F2F2;} -td{color: #3D3D3D;line-height: 2.0;text-align: left;padding: 0 0.5em;} -td.borderLC{border-left:1px solid #3D3D3D;text-align:center;} -td.borderLL{border-left:1px solid #3D3D3D;text-align:left;} -td.borderRL{border-right:1px solid #3D3D3D;text-align:left;} -td.borderRW{border-right:1px solid #FFF} -td.borderLW{border-left:1px solid #FFF;} -td.centerW{text-align:center;color:#FFF;} -td.center{text-align:center;color:#3D3D3D;} -tr.bgcolor{background-color:#A94442;} -h1.left{text-align:left;margin-left:20px;} -table.small{width:40%;background-color:#FFF; -margin-left:20px;margin-bottom:30px;} -table.small{width:40%;background-color:#FFF; -margin-left:20px;margin-bottom:30px;} -td.col_headR{background-color:#A94442; -line-height:3.0;color:#FFF;border-right:1px solid #FFF;} -td.col_head{background-color:#A94442; -line-height:3.0;color:#FFF;} -b.title{margin-left:20px;font-weight:bold;line-height:2.0;} -input.button{margin-left:20px;margin-top:4px; -font-size:20px;width:80px;height:60px;} -td.head{text-align:center;color:#FFF;line-height:3.0;}` - -// Mux creates zpages mux to serve at prefixed path. -// If traceToURL is not nil, sampled traces are converted to URLs (URL could -// lead to Jaeger instance for example). -func Mux(prefix string, traceToURL func(traceID string) string) http.Handler { +// Mux creates a tracez mux to serve at prefixed path. +func Mux(prefix string, sp *otelzpages.SpanProcessor, _ func(traceID string) string) http.Handler { mux := http.NewServeMux() - zpages.Handle(mux, prefix+"/") - - sampledTraces := regexp.MustCompile(`([a-z0-9]{32})`) - - return http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) { - // hijacking css - if req.RequestURI == prefix+"/public/opencensus.css" { - rw.Header().Set("Content-Type", "text/css; charset=utf-8") - - _, err := rw.Write([]byte(css)) - if err != nil { - panic(err) - } - - return - } - - w := httptest.NewRecorder() - - mux.ServeHTTP(w, req) - body := bytes.Replace( - w.Body.Bytes(), - []byte(`//www.opencensus.io/favicon.ico`), - []byte(`https://opencensus.io/images/favicon.ico`), - 1, - ) - - if traceToURL != nil { - matches := sampledTraces.FindAllStringSubmatch(string(body), -1) - for _, m := range matches { - url := traceToURL(m[1]) - body = bytes.Replace(body, []byte(m[1]), []byte(``+m[1]+``), 1) - } - } + mux.Handle(prefix+"/tracez", otelzpages.NewTracezHandler(sp)) + mux.Handle(prefix+"/tracez/", otelzpages.NewTracezHandler(sp)) - _, err := rw.Write(body) - if err != nil { - panic(err) - } - }) + return mux } diff --git a/go.mod b/go.mod index 442acf4..2f3f108 100644 --- a/go.mod +++ b/go.mod @@ -1,92 +1,108 @@ module github.com/bool64/brick -go 1.22.7 +go 1.25.0 require ( - contrib.go.opencensus.io/exporter/jaeger v0.2.1 - contrib.go.opencensus.io/exporter/prometheus v0.4.2 - contrib.go.opencensus.io/integrations/ocsql v0.1.7 github.com/Masterminds/squirrel v1.5.4 - github.com/bool64/cache v0.4.8 + github.com/XSAM/otelsql v0.42.0 + github.com/bool64/cache v0.5.0 github.com/bool64/ctxd v1.2.1 github.com/bool64/dbwrap v0.1.4 - github.com/bool64/dev v0.2.39 + github.com/bool64/dev v0.2.45 github.com/bool64/godogx v0.1.1 github.com/bool64/httpmock v0.1.15 github.com/bool64/logz v1.3.2 github.com/bool64/prom-stats v0.1.3 - github.com/bool64/shared v0.1.5 - github.com/bool64/sqluct v0.2.4 + github.com/bool64/shared v0.1.6 + github.com/bool64/sqluct v0.2.8 github.com/bool64/stats v0.2.2 github.com/bool64/zapctxd v1.2.0 - github.com/cucumber/godog v0.15.0 - github.com/go-chi/chi/v5 v5.2.1 + github.com/cucumber/godog v0.15.1 + github.com/go-chi/chi/v5 v5.2.5 github.com/godogx/allure v0.2.4 - github.com/godogx/dbsteps v0.1.3 - github.com/godogx/httpsteps v0.2.16 - github.com/godogx/vars v0.1.8 + github.com/godogx/dbsteps v0.1.9 + github.com/godogx/httpsteps v0.2.19 + github.com/godogx/vars v0.1.11 github.com/jmoiron/sqlx v1.4.0 github.com/joho/godotenv v1.5.1 github.com/kelseyhightower/envconfig v1.4.0 - github.com/prometheus/client_golang v1.20.5 + github.com/prometheus/client_golang v1.23.2 github.com/santhosh-tekuri/jsonschema/v3 v3.1.0 - github.com/stretchr/testify v1.10.0 - github.com/swaggest/assertjson v1.9.0 - github.com/swaggest/jsonschema-go v0.3.73 - github.com/swaggest/openapi-go v0.2.55 - github.com/swaggest/rest v0.2.72 - github.com/swaggest/swgui v1.8.4 + github.com/stretchr/testify v1.11.1 + github.com/swaggest/assertjson v1.10.0 + github.com/swaggest/jsonschema-go v0.3.79 + github.com/swaggest/openapi-go v0.2.61 + github.com/swaggest/rest v0.2.75 + github.com/swaggest/swgui v1.8.7 github.com/swaggest/usecase v1.3.1 github.com/vearutop/gooselite v0.1.1 - go.opencensus.io v0.24.0 - go.uber.org/zap v1.27.0 + go.opentelemetry.io/contrib/bridges/otelslog v0.18.0 + go.opentelemetry.io/contrib/bridges/prometheus v0.68.0 + go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.68.0 + go.opentelemetry.io/contrib/zpages v0.68.0 + go.opentelemetry.io/otel v1.43.0 + go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.19.0 + go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.43.0 + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.43.0 + go.opentelemetry.io/otel/exporters/prometheus v0.65.0 + go.opentelemetry.io/otel/sdk v1.43.0 + go.opentelemetry.io/otel/sdk/log v0.19.0 + go.opentelemetry.io/otel/sdk/metric v1.43.0 + go.opentelemetry.io/otel/trace v1.43.0 + go.uber.org/zap v1.28.0 ) require ( github.com/beorn7/perks v1.0.1 // indirect github.com/cenkalti/backoff/v4 v4.3.0 // indirect + github.com/cenkalti/backoff/v5 v5.0.3 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/cucumber/gherkin/go/v26 v26.2.0 // indirect github.com/cucumber/messages/go/v21 v21.0.1 // indirect github.com/davecgh/go-spew v1.1.1 // indirect - github.com/go-kit/log v0.2.1 // indirect - github.com/go-logfmt/logfmt v0.5.1 // indirect + github.com/felixge/httpsnoop v1.0.4 // indirect + github.com/go-logr/logr v1.4.3 // indirect + github.com/go-logr/stdr v1.2.2 // indirect github.com/godogx/resource v0.1.1 // indirect github.com/gofrs/uuid v4.4.0+incompatible // indirect - github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/google/uuid v1.6.0 // indirect + github.com/grpc-ecosystem/grpc-gateway/v2 v2.28.0 // indirect github.com/hashicorp/go-immutable-radix v1.3.1 // indirect - github.com/hashicorp/go-memdb v1.3.4 // indirect + github.com/hashicorp/go-memdb v1.3.5 // indirect github.com/hashicorp/golang-lru v1.0.2 // indirect github.com/iancoleman/orderedmap v0.3.0 // indirect - github.com/klauspost/compress v1.17.9 // indirect github.com/lann/builder v0.0.0-20180802200727-47ae307949d0 // indirect github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect - github.com/prometheus/client_model v0.6.1 // indirect - github.com/prometheus/common v0.55.0 // indirect - github.com/prometheus/procfs v0.15.1 // indirect - github.com/prometheus/statsd_exporter v0.22.8 // indirect - github.com/sergi/go-diff v1.3.1 // indirect - github.com/spf13/pflag v1.0.6 // indirect + github.com/prometheus/client_model v0.6.2 // indirect + github.com/prometheus/common v0.67.5 // indirect + github.com/prometheus/otlptranslator v1.0.0 // indirect + github.com/prometheus/procfs v0.20.1 // indirect + github.com/sergi/go-diff v1.4.0 // indirect + github.com/spf13/pflag v1.0.10 // indirect github.com/swaggest/form/v5 v5.1.1 // indirect - github.com/swaggest/refl v1.3.0 // indirect - github.com/uber/jaeger-client-go v2.25.0+incompatible // indirect + github.com/swaggest/refl v1.4.0 // indirect github.com/vearutop/dynhist-go v1.2.3 // indirect github.com/vearutop/lograte v1.2.0 // indirect github.com/yalp/jsonpath v0.0.0-20180802001716-5cc68e5049a0 // indirect github.com/yosuke-furukawa/json5 v0.1.2-0.20201207051438-cf7bb3f354ff // indirect - github.com/yudai/gojsondiff v1.0.0 // indirect github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82 // indirect + go.opentelemetry.io/auto/sdk v1.2.1 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.43.0 // indirect + go.opentelemetry.io/otel/log v0.19.0 // indirect + go.opentelemetry.io/otel/metric v1.43.0 // indirect + go.opentelemetry.io/proto/otlp v1.10.0 // indirect go.uber.org/multierr v1.11.0 // indirect - golang.org/x/sync v0.11.0 // indirect - golang.org/x/sys v0.30.0 // indirect - google.golang.org/api v0.221.0 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20250212204824-5a70512c5d8b // indirect - google.golang.org/grpc v1.70.0 // indirect - google.golang.org/protobuf v1.36.5 // indirect + go.yaml.in/yaml/v2 v2.4.4 // indirect + golang.org/x/net v0.52.0 // indirect + golang.org/x/sys v0.42.0 // indirect + golang.org/x/text v0.35.0 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20260414002931-afd174a4e478 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20260414002931-afd174a4e478 // indirect + google.golang.org/grpc v1.80.0 // indirect + google.golang.org/protobuf v1.36.11 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/go.sum b/go.sum index cba54ed..c7570d8 100644 --- a/go.sum +++ b/go.sum @@ -5,38 +5,11 @@ cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6A cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= -cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= -cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4= -cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M= -cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc= -cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk= -cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs= -cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc= -cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY= cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= -cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= -cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= -cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= -cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= -cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= -cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk= cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= -cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= -cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= -cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU= cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= -cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= -cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= -cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= -cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= -contrib.go.opencensus.io/exporter/jaeger v0.2.1 h1:yGBYzYMewVL0yO9qqJv3Z5+IRhPdU7e9o/2oKpX4YvI= -contrib.go.opencensus.io/exporter/jaeger v0.2.1/go.mod h1:Y8IsLgdxqh1QxYxPC5IgXVmBaeLUeQFfBeBi9PbeZd0= -contrib.go.opencensus.io/exporter/prometheus v0.4.2 h1:sqfsYl5GIY/L570iT+l93ehxaWJs2/OwXtiWwew3oAg= -contrib.go.opencensus.io/exporter/prometheus v0.4.2/go.mod h1:dvEHbiKmgvbr5pjaF9fpw1KeYcjrnC1J8B+JKjsZyRQ= -contrib.go.opencensus.io/integrations/ocsql v0.1.7 h1:G3k7C0/W44zcqkpRSFyjU9f6HZkbwIrL//qqnlqWZ60= -contrib.go.opencensus.io/integrations/ocsql v0.1.7/go.mod h1:8DsSdjz3F+APR+0z0WkU1aRorQCFfRxvqjUUPMbF3fE= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA= filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4= @@ -48,12 +21,10 @@ github.com/DATA-DOG/go-sqlmock v1.5.2/go.mod h1:88MAG/4G7SMwSE3CeA0ZKzrT5CiOU3OJ github.com/Masterminds/squirrel v1.5.4 h1:uUcX/aBc8O7Fg9kaISIUsHXdKuqehiXAMQTYX8afzqM= github.com/Masterminds/squirrel v1.5.4/go.mod h1:NNaOrjSoIDfDA40n7sr2tPNZRfjzjA400rg+riTZj10= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= +github.com/XSAM/otelsql v0.42.0 h1:Li0xF4eJUxG2e0x3D4rvRlys1f27yJKvjTh7ljkUP5o= +github.com/XSAM/otelsql v0.42.0/go.mod h1:4mOrEv+cS1KmKzrvTktvJnstr5GtKSAK+QHvFR9OcpI= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= -github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= -github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= -github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= -github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137/go.mod h1:OMCwj8VM1Kc9e19TLln2VL61YJF0x1XFtfdL4JdbSyE= github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= @@ -63,8 +34,8 @@ github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84= -github.com/bool64/cache v0.4.8 h1:dtGeGYMXuOJ22CzQD1Wh0djxUWt2yH+4nXAryw+0ecs= -github.com/bool64/cache v0.4.8/go.mod h1:kU7S7UMotUL5CReSpHK/QRwYDqowH7XKT31nbLOHZXc= +github.com/bool64/cache v0.5.0 h1:cjNTHc4m5V4A5sd1Pp5EQVnOBenxVfS0RfpljIvexXg= +github.com/bool64/cache v0.5.0/go.mod h1:10SzDo9UAaurdUz0tJo48X4G6iSmevbm87M3tD0OerU= github.com/bool64/ctxd v1.2.1 h1:hARFteq0zdn4bwfmxLhak3fXFuvtJVKDH2X29VV/2ls= github.com/bool64/ctxd v1.2.1/go.mod h1:ZG6QkeGVLTiUl2mxPpyHmFhDzFZCyocr9hluBV3LYuc= github.com/bool64/dbwrap v0.1.4 h1:8jT6yArRzJy06Ox/EuzfYpBrBAF+pW0uDXygeLMX1iU= @@ -74,8 +45,8 @@ github.com/bool64/dev v0.1.38/go.mod h1:cTHiTDNc8EewrQPy3p1obNilpMpdmlUesDkFTF2z github.com/bool64/dev v0.2.4/go.mod h1:cTHiTDNc8EewrQPy3p1obNilpMpdmlUesDkFTF2zRWU= github.com/bool64/dev v0.2.25/go.mod h1:iJbh1y/HkunEPhgebWRNcs8wfGq7sjvJ6W5iabL8ACg= github.com/bool64/dev v0.2.36/go.mod h1:iJbh1y/HkunEPhgebWRNcs8wfGq7sjvJ6W5iabL8ACg= -github.com/bool64/dev v0.2.39 h1:kP8DnMGlWXhGYJEZE/J0l/gVBdbuhoPGL+MJG4QbofE= -github.com/bool64/dev v0.2.39/go.mod h1:iJbh1y/HkunEPhgebWRNcs8wfGq7sjvJ6W5iabL8ACg= +github.com/bool64/dev v0.2.45 h1:3nLKhAS/6Oklk3Mt2lHYSN/Cb4tdAD77KLwzeP+6eYE= +github.com/bool64/dev v0.2.45/go.mod h1:iJbh1y/HkunEPhgebWRNcs8wfGq7sjvJ6W5iabL8ACg= github.com/bool64/godogx v0.1.1 h1:iAwnix6HQgl7A5BAJ4mMvWbhR721GHNxeAAKFEjrWO4= github.com/bool64/godogx v0.1.1/go.mod h1:qydmzRfimgYTmNEvpnc+SJNkmdjpPoPavYQoSn2rjoY= github.com/bool64/httpmock v0.1.15 h1:PWvuqpew/FEigT7cvv03/t9G+UeE3wD2QP8PVyBBUwc= @@ -84,27 +55,22 @@ github.com/bool64/logz v1.3.2 h1:v18HgZ7Q0WbV2jk3V4fwVpThZcmf/eNFN1EMeLLhFpc= github.com/bool64/logz v1.3.2/go.mod h1:4+kS446aeINYBwX5QsOgz8mBBwW/9IEI1Q/FV3wHYDU= github.com/bool64/prom-stats v0.1.3 h1:ZmqTpW1CWFO1zO1z2Fa2GNScEYLAQLc7uoYOcw54he8= github.com/bool64/prom-stats v0.1.3/go.mod h1:uAydOHn7rCblxGm4TkhSAFjTOsTgduxMIVB8yh8Ja7I= -github.com/bool64/shared v0.1.5 h1:fp3eUhBsrSjNCQPcSdQqZxxh9bBwrYiZ+zOKFkM0/2E= -github.com/bool64/shared v0.1.5/go.mod h1:081yz68YC9jeFB3+Bbmno2RFWvGKv1lPKkMP6MHJlPs= -github.com/bool64/sqluct v0.2.4 h1:4dpa3/k0v+V9mUN2SHzCgmMAH0iqhHczXg9e8YuoWwY= -github.com/bool64/sqluct v0.2.4/go.mod h1:3HQviUcavzBhDAC2tX5MYvvTMFSLVDPMOHVj6QWiUkM= +github.com/bool64/shared v0.1.6 h1:1u1IfTU84pZU285Mf1kQC5wX/VzSRE5E/+4KgFRGQ6o= +github.com/bool64/shared v0.1.6/go.mod h1:AByMlOFBjavJDk8VdFBH/atMgv1q7qrKXD1XLAQTgZA= +github.com/bool64/sqluct v0.2.8 h1:ZUBkCm4hekyYNE0HEC8H+z5oQX7LVeDt7Oasrh+fp9Y= +github.com/bool64/sqluct v0.2.8/go.mod h1:DY6C6ehBuKrT8vTQeiKwBdC022bUcfpkDKUSdog1DXQ= github.com/bool64/stats v0.2.2 h1:BRfpJk/4KKMo4K+c9jv4aGemyekHCvCQFRljbmHC7gk= github.com/bool64/stats v0.2.2/go.mod h1:MlIBXxLmuimNc8EDnB3XAYDN+suGvgv+XUUwrFelAA4= github.com/bool64/zapctxd v1.2.0 h1:HVlATfuXzxppbWnpvVWhz1exG+Ntsy8uSF7GE6Pf3T4= github.com/bool64/zapctxd v1.2.0/go.mod h1:NT/Cg8PP11T7Sqd5QNW0HA/wo59uZBWImLhGSX9tLQw= 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/cenkalti/backoff/v5 v5.0.3 h1:ZN+IMa753KfX5hd8vVaMixjnqRZ3y8CuJKRKj1xcsSM= +github.com/cenkalti/backoff/v5 v5.0.3/go.mod h1:rkhZdG3JZukswDf7f0cwqPNk4K0sa+F97BxZthm/crw= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= -github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= 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/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= -github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= -github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= 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/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= @@ -116,8 +82,8 @@ github.com/cucumber/gherkin-go/v19 v19.0.3/go.mod h1:jY/NP6jUtRSArQQJ5h1FXOUgk5f github.com/cucumber/gherkin/go/v26 v26.2.0 h1:EgIjePLWiPeslwIWmNQ3XHcypPsWAHoMCz/YEBKP4GI= github.com/cucumber/gherkin/go/v26 v26.2.0/go.mod h1:t2GAPnB8maCT4lkHL99BDCVNzCh1d7dBhCLt150Nr/0= github.com/cucumber/godog v0.12.0/go.mod h1:u6SD7IXC49dLpPN35kal0oYEjsXZWee4pW6Tm9t5pIc= -github.com/cucumber/godog v0.15.0 h1:51AL8lBXF3f0cyA5CV4TnJFCTHpgiy+1x1Hb3TtZUmo= -github.com/cucumber/godog v0.15.0/go.mod h1:FX3rzIDybWABU4kuIXLZ/qtqEe1Ac5RdXmqvACJOces= +github.com/cucumber/godog v0.15.1 h1:rb/6oHDdvVZKS66hrhpjFQFHjthFSrQBCOI1LwshNTI= +github.com/cucumber/godog v0.15.1/go.mod h1:qju+SQDewOljHuq9NSM66s0xEhogx0q30flfxL4WUk8= github.com/cucumber/messages-go/v16 v16.0.0/go.mod h1:EJcyR5Mm5ZuDsKJnT2N9KRnBK30BGjtYotDKpwQ0v6g= github.com/cucumber/messages-go/v16 v16.0.1/go.mod h1:EJcyR5Mm5ZuDsKJnT2N9KRnBK30BGjtYotDKpwQ0v6g= github.com/cucumber/messages/go/v21 v21.0.1 h1:wzA0LxwjlWQYZd32VTlAVDTkW6inOFmSM+RuOwHZiMI= @@ -128,44 +94,37 @@ 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/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= -github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= -github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= -github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= -github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= +github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +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.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= -github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= -github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= -github.com/go-chi/chi/v5 v5.2.1 h1:KOIHODQj58PmL80G2Eak4WdvUzjSJSm0vG72crDCqb8= -github.com/go-chi/chi/v5 v5.2.1/go.mod h1:L2yAIGWB3H+phAw1NxKwWM+7eUH/lU8pOMm5hHcoops= +github.com/go-chi/chi/v5 v5.2.5 h1:Eg4myHZBjyvJmAFjFvWgrqDTXFyOzjj7YIm3L3mu6Ug= +github.com/go-chi/chi/v5 v5.2.5/go.mod h1:X7Gx4mteadT3eDOMTsXzmI4/rwUpOwBHLpAfupzFJP0= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= -github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= -github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= -github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= -github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= -github.com/go-kit/log v0.2.0/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0= -github.com/go-kit/log v0.2.1 h1:MRVx0/zhvdseW+Gza6N9rVzU/IVzaeE1SFI4raAhmBU= -github.com/go-kit/log v0.2.1/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= -github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= -github.com/go-logfmt/logfmt v0.5.1 h1:otpy5pqBCBZ1ng9RQ0dPu4PN7ba75Y/aA+UpowDyNVA= -github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs= +github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +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-sql-driver/mysql v1.8.1 h1:LedoTUt/eveggdHS9qUFC1EFSa8bU2+1pZjSRpvNJ1Y= github.com/go-sql-driver/mysql v1.8.1/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/godogx/allure v0.2.4 h1:0Vq3ah2soX9kaQBBeROXThzjmVQYFHDPm5ZnKjNwJIY= github.com/godogx/allure v0.2.4/go.mod h1:AgMrcvgg+Ueyc6Jg75oySZZMFsiw4YOtQ728OkLFoKA= -github.com/godogx/dbsteps v0.1.3 h1:rno+ArRmreckJE58JW8pNBupepcWXQQp9TtDV0s8PqE= -github.com/godogx/dbsteps v0.1.3/go.mod h1:5GK1OK0nFqKUEoAn0lKbhXSZLGs9qnMJhAaO3WsCbW8= -github.com/godogx/httpsteps v0.2.16 h1:Q7i7SXGefYtmRNeZEjKDNoBXH/UBdLIP0ffrcbmVj30= -github.com/godogx/httpsteps v0.2.16/go.mod h1:RIZDVkf3IchEDweNt1nPMRxQA8+alaNCRLX+xsbRb7I= +github.com/godogx/dbsteps v0.1.9 h1:96Cb5S6Sk3AVGNTQxIKbvgt9oXqymBxtob95oP9/Rmo= +github.com/godogx/dbsteps v0.1.9/go.mod h1:KkGGAPc446Djgrt0XbGRpRfRDXpYC661PVV5xNYI5hY= +github.com/godogx/httpsteps v0.2.19 h1:7yfIuAiCYhyzxttJt6hsOFuCqGxMblZEpzj/nlDHfYs= +github.com/godogx/httpsteps v0.2.19/go.mod h1:Sj0NPRjQtChdJiv7vFQqxKi+9bjb/+iQhrSP6Af0qzc= github.com/godogx/resource v0.1.1 h1:1vbznIn1mUCP+9TzJp9v8QKm54kAMTe38CBLnFBk0j8= github.com/godogx/resource v0.1.1/go.mod h1:OYaiyttuq2KaiJp2yOMekyOFjZJFz3w/D7WPioUVC4Y= -github.com/godogx/vars v0.1.8 h1:UtAnTBpbZ5E9hm+SeEtk3atgrNlKd4D0gG4r4sZgE3w= -github.com/godogx/vars v0.1.8/go.mod h1:dVfTTDjNvAul6VqXgSogRTw+dvh8+v2lWrCdXOqUFEY= +github.com/godogx/vars v0.1.11 h1:Maae8QtGzCoZlTsuaXwZaEz1MGPvNMtC1O18s4Z8fpw= +github.com/godogx/vars v0.1.11/go.mod h1:UL4jj0Z1Xs61nNE/VS4vMYZowISPCpvlYZ85EgdFQ8Q= github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= github.com/gofrs/uuid v4.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= github.com/gofrs/uuid v4.3.1+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= @@ -175,63 +134,24 @@ github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7a github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= -github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= -github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= -github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= -github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= -github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= -github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= -github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= -github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= -github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= -github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= -github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= -github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= -github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= -github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= -github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= -github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= -github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -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/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= +github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= -github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= -github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= -github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= 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= @@ -242,6 +162,8 @@ github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/ad github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.28.0 h1:HWRh5R2+9EifMyIHV7ZV+MIZqgz+PMpZ14Jynv3O2Zs= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.28.0/go.mod h1:JfhWUomR1baixubs02l85lZYYOm7LV6om4ceouMv45c= github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q= github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= @@ -251,8 +173,9 @@ github.com/hashicorp/go-immutable-radix v1.3.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjh github.com/hashicorp/go-immutable-radix v1.3.1 h1:DKHmCUm2hRBK510BaiZlwvpD40f8bJFeZnpfm2KLowc= github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= github.com/hashicorp/go-memdb v1.3.0/go.mod h1:Mluclgwib3R93Hk5fxEfiRhB+6Dar64wWh71LpNSe3g= -github.com/hashicorp/go-memdb v1.3.4 h1:XSL3NR682X/cVk2IeV0d70N4DZ9ljI885xAEU8IoK3c= github.com/hashicorp/go-memdb v1.3.4/go.mod h1:uBTr1oQbtuMgd1SSGoR8YV27eT3sBHbYiNm53bMpgSg= +github.com/hashicorp/go-memdb v1.3.5 h1:b3taDMxCBCBVgyRrS1AZVHO14ubMYZB++QpNhBg+Nyo= +github.com/hashicorp/go-memdb v1.3.5/go.mod h1:8IVKKBkVe+fxFgdFOYxzQQNjz+sWCyHCdIC/+5+Vy1Y= github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU= @@ -275,7 +198,6 @@ github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2p github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc= github.com/iancoleman/orderedmap v0.3.0 h1:5cbR2grmZR/DiVt+VJopEhtVs9YGInGIxAoMJn+Ichc= github.com/iancoleman/orderedmap v0.3.0/go.mod h1:XuLcCUkdL5owUCQeF2Ue9uuw1EptkJDkXXS7VoV7XGE= -github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/jmoiron/sqlx v1.4.0 h1:1PLqN7S1UYp5t4SrVVnt4nUVNemrDAtxlulVe+Qgm3o= @@ -283,24 +205,17 @@ github.com/jmoiron/sqlx v1.4.0/go.mod h1:ZrZ7UsYB/weZdl2Bxg6jCRO9c3YHl8r3ahlKmRT github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= -github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= -github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= -github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= -github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= -github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= -github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= github.com/kelseyhightower/envconfig v1.4.0 h1:Im6hONhd3pLkfDFsbRgu68RDNkGF1r3dvMUtDTo2cv8= github.com/kelseyhightower/envconfig v1.4.0/go.mod h1:cccZRl6mQpaq41TPp5QxidR+Sa3axMbJDNb//FQX6Gg= github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= -github.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA= -github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw= +github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo= +github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= -github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= @@ -320,8 +235,6 @@ github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw= github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= -github.com/mattn/go-colorable v0.1.8 h1:c1ghPdyEDarC70ftn0y+A/Ee++9zz8ljHG1b13eJ0s8= -github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= @@ -338,22 +251,14 @@ github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS4 github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY= github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= -github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= -github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= -github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= 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/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= -github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= -github.com/nxadm/tail v1.4.11 h1:8feyoE3OzPrcshW5/MJ4sGESc5cqmGkGCWlco4l0bqY= -github.com/nxadm/tail v1.4.11/go.mod h1:OTaG3NK980DZzxbRq6lEuzgU+mug70nY11sMd4JXXHc= +github.com/ncruces/go-strftime v1.0.0 h1:HMFp8mLCTPp341M/ZnA4qaf7ZlsbTc+miZjCLOFAw7w= +github.com/ncruces/go-strftime v1.0.0/go.mod h1:Fwc5htZGVVkseilnfgOVb9mKy6w1naJmn9CehxcKcls= github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= -github.com/onsi/ginkgo v1.15.2 h1:l77YT15o814C2qVL47NOyjV/6RbaP7kKdrvZnxQ3Org= -github.com/onsi/ginkgo v1.15.2/go.mod h1:Dd6YFfwBW84ETqqtL0CPyPXillHgY6XhQH3uuCCTr/o= -github.com/onsi/gomega v1.11.0 h1:+CqWgvj0OZycCaqclBD1pxKHAU+tOkHmQIWvDHq2aug= -github.com/onsi/gomega v1.11.0/go.mod h1:azGKhqFUon9Vuj0YmTfLSmx0FUwqXYSTl5re8lQLTUg= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= @@ -365,59 +270,39 @@ github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZN github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso= -github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= -github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= -github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= -github.com/prometheus/client_golang v1.12.1/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY= -github.com/prometheus/client_golang v1.12.2/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY= -github.com/prometheus/client_golang v1.13.0/go.mod h1:vTeo+zgvILHsnnj/39Ou/1fPN5nJFOEMgftOUOmlvYQ= -github.com/prometheus/client_golang v1.20.5 h1:cxppBPuYhUnsO6yo/aoRol4L7q7UFfdm+bR9r+8l63Y= -github.com/prometheus/client_golang v1.20.5/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE= +github.com/prometheus/client_golang v1.23.2 h1:Je96obch5RDVy3FDMndoUsjAhG5Edi49h0RJWRi/o0o= +github.com/prometheus/client_golang v1.23.2/go.mod h1:Tb1a6LWHB3/SPIzCoaDXI4I8UHKeFTEQ1YCr+0Gyqmg= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E= -github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY= +github.com/prometheus/client_model v0.6.2 h1:oBsgwpGs7iVziMvrGhE53c/GrLUsZdHnqNwqPLxwZyk= +github.com/prometheus/client_model v0.6.2/go.mod h1:y3m2F6Gdpfy6Ut/GBsUqTWZqCUvMVzSfMLjcu6wAwpE= github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= -github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= -github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= -github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc= -github.com/prometheus/common v0.32.1/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls= -github.com/prometheus/common v0.35.0/go.mod h1:phzohg0JFMnBEFGxTDbfu3QyL5GI8gTQJFhYO5B3mfA= -github.com/prometheus/common v0.37.0/go.mod h1:phzohg0JFMnBEFGxTDbfu3QyL5GI8gTQJFhYO5B3mfA= -github.com/prometheus/common v0.55.0 h1:KEi6DK7lXW/m7Ig5i47x0vRzuBsHuvJdi5ee6Y3G1dc= -github.com/prometheus/common v0.55.0/go.mod h1:2SECS4xJG1kd8XF9IcM1gMX6510RAEL65zxzNImwdc8= +github.com/prometheus/common v0.67.5 h1:pIgK94WWlQt1WLwAC5j2ynLaBRDiinoAb86HZHTUGI4= +github.com/prometheus/common v0.67.5/go.mod h1:SjE/0MzDEEAyrdr5Gqc6G+sXI67maCxzaT3A2+HqjUw= +github.com/prometheus/otlptranslator v1.0.0 h1:s0LJW/iN9dkIH+EnhiD3BlkkP5QVIUVEoIwkU+A6qos= +github.com/prometheus/otlptranslator v1.0.0/go.mod h1:vRYWnXvI6aWGpsdY/mOT/cbeVRBlPWtBNDb7kGR3uKM= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= -github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= -github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= -github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= -github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= -github.com/prometheus/procfs v0.8.0/go.mod h1:z7EfXMXOkbkqb9IINtpCn86r/to3BnA0uaxHdg830/4= -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/prometheus/statsd_exporter v0.22.7/go.mod h1:N/TevpjkIh9ccs6nuzY3jQn9dFqnUakOjnEuMPJJJnI= -github.com/prometheus/statsd_exporter v0.22.8 h1:Qo2D9ZzaQG+id9i5NYNGmbf1aa/KxKbB9aKfMS+Yib0= -github.com/prometheus/statsd_exporter v0.22.8/go.mod h1:/DzwbTEaFTE0Ojz5PqcSk6+PFHOPWGxdXVr6yC8eFOM= +github.com/prometheus/procfs v0.20.1 h1:XwbrGOIplXW/AU3YhIhLODXMJYyC1isLFfYCsTEycfc= +github.com/prometheus/procfs v0.20.1/go.mod h1:o9EMBZGRyvDrSPH1RqdxhojkuXstoe4UlK79eF5TGGo= github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= +github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE= +github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= -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/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ= +github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc= 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/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= github.com/santhosh-tekuri/jsonschema/v3 v3.1.0 h1:levPcBfnazlA1CyCMC3asL/QLZkq9pa8tQZOH513zQw= github.com/santhosh-tekuri/jsonschema/v3 v3.1.0/go.mod h1:8kzK2TC0k0YjOForaAHdNEa7ik0fokNa2k30BKJ/W7Y= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= -github.com/sergi/go-diff v1.3.1 h1:xkr+Oxo4BOQKmkn/B9eMK0g5Kg/983T9DqqPHwYqD+8= -github.com/sergi/go-diff v1.3.1/go.mod h1:aMJSSKb2lpPvRNec0+w3fl7LP9IOFzdc9Pa4NFbPK1I= +github.com/sergi/go-diff v1.4.0 h1:n/SP9D5ad1fORl+llWyN+D6qoUETXNZARKjyY2/KVCw= +github.com/sergi/go-diff v1.4.0/go.mod h1:A0bzQcvG0E7Rwjx0REVgAGH58e96+X0MeOfepqsbeW4= 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.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= -github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= @@ -429,8 +314,9 @@ github.com/spf13/cobra v1.7.0/go.mod h1:uLxZILRyS/50WlhOIKD7W6V5bgeIt+4sICxh6uRM github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= -github.com/spf13/pflag v1.0.6 h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o= -github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/pflag v1.0.7/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/pflag v1.0.10 h1:4EBh2KAYBwaONj6b2Ye1GiHfwjqyROoF4RwYO+vPwFk= +github.com/spf13/pflag v1.0.10/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= @@ -439,35 +325,31 @@ github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpE github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= -github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= -github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= -github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= -github.com/stvp/go-udp-testing v0.0.0-20201019212854-469649b16807/go.mod h1:7jxmlfBCDBXRzr0eAQJ48XC1hBu1np4CS5+cHEYfwpc= +github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= +github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= -github.com/swaggest/assertjson v1.9.0 h1:dKu0BfJkIxv/xe//mkCrK5yZbs79jL7OVf9Ija7o2xQ= -github.com/swaggest/assertjson v1.9.0/go.mod h1:b+ZKX2VRiUjxfUIal0HDN85W0nHPAYUbYH5WkkSsFsU= +github.com/swaggest/assertjson v1.10.0 h1:OYIx29UbgqjwAekKbeIO8T0XbAMyViJ8qqrVj2GQY2M= +github.com/swaggest/assertjson v1.10.0/go.mod h1:31+ufMpzrCO/daIRZ4s1UZAA1R2q9EEUfJaoczgAty8= github.com/swaggest/form/v5 v5.1.1 h1:ct6/rOQBGrqWUQ0FUv3vW5sHvTUb31AwTUWj947N6cY= github.com/swaggest/form/v5 v5.1.1/go.mod h1:X1hraaoONee20PMnGNLQpO32f9zbQ0Czfm7iZThuEKg= -github.com/swaggest/jsonschema-go v0.3.73 h1:gU1pBzF3pkZ1GDD3dRMdQoCjrA0sldJ+QcM7aSSPgvc= -github.com/swaggest/jsonschema-go v0.3.73/go.mod h1:qp+Ym2DIXHlHzch3HKz50gPf2wJhKOrAB/VYqLS2oJU= -github.com/swaggest/openapi-go v0.2.55 h1:PI9r7E8l0iKHriqQ6QxLbTjkZyUIHA8rlpzatYZff3c= -github.com/swaggest/openapi-go v0.2.55/go.mod h1:sTmhR2sTvauaRX45WdaqRyJVTfRQ5FxD4OPVym49BXM= -github.com/swaggest/refl v1.3.0 h1:PEUWIku+ZznYfsoyheF97ypSduvMApYyGkYF3nabS0I= -github.com/swaggest/refl v1.3.0/go.mod h1:3Ujvbmh1pfSbDYjC6JGG7nMgPvpG0ehQL4iNonnLNbg= -github.com/swaggest/rest v0.2.72 h1:eaHg2hzD+vBVPmt44dNq9fdMz0UF6QNX+Nca36SDOq4= -github.com/swaggest/rest v0.2.72/go.mod h1:oXW3+1intYTcTxrZH5snFgme+mud4Qy6iTFY34pqATg= -github.com/swaggest/swgui v1.8.4 h1:iYxPCG69hLajio0/6vey0245AM+fvpT4ENhiFXb+KMU= -github.com/swaggest/swgui v1.8.4/go.mod h1:ct+lyINt6I70raCWwmqfgZ0ZMu3OAF4DRwrg32DDwJY= +github.com/swaggest/jsonschema-go v0.3.79 h1:0TOShCbAJ9Xjt1e2W83l+QtMQSG2pbun2EkiYTyafCs= +github.com/swaggest/jsonschema-go v0.3.79/go.mod h1:GqVmJ+XNLeUHhFIhHNKc+C68euxfrl3a3aoZH4vTRl0= +github.com/swaggest/openapi-go v0.2.61 h1:psc+LE7pWhEjmJpmkti9tUmBPkkobdUNflBf5Ps6JSc= +github.com/swaggest/openapi-go v0.2.61/go.mod h1:786CwSwleh1IorB0nfwYGESWf83JgQh6fBc1PeJe4Iw= +github.com/swaggest/refl v1.4.0 h1:CftOSdTqRqs100xpFOT/Rifss5xBV/CT0S/FN60Xe9k= +github.com/swaggest/refl v1.4.0/go.mod h1:4uUVFVfPJ0NSX9FPwMPspeHos9wPFlCMGoPRllUbpvA= +github.com/swaggest/rest v0.2.75 h1:MW9zZ3d0kduJ2KdWnSYZIIrZJ1v3Kg+S7QZrDCZcXws= +github.com/swaggest/rest v0.2.75/go.mod h1:yw+PNgpNSdD6W46r60keVXdsBB+7SKt64i2qpeuBsq4= +github.com/swaggest/swgui v1.8.7 h1:8heNQUBnmAbF0ah87sJAipP8KjmttVgzt/r5RcVOD54= +github.com/swaggest/swgui v1.8.7/go.mod h1:eTJfgwudbyw9xMwqO26vs82ei2u6//JnUAofx2vGB3M= github.com/swaggest/usecase v1.3.1 h1:JdKV30MTSsDxAXxkldLNcEn8O2uf565khyo6gr5sS+w= github.com/swaggest/usecase v1.3.1/go.mod h1:cae3lDd5VDmM36OQcOOOdAlEDg40TiQYIp99S9ejWqA= github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= -github.com/uber/jaeger-client-go v2.25.0+incompatible h1:IxcNZ7WRY1Y3G4poYlx24szfsn/3LvK9QHCq9oQw8+U= -github.com/uber/jaeger-client-go v2.25.0+incompatible/go.mod h1:WVhlPFC8FDjOFMMWRy2pZqQJSXxYSwNYOkTr/Z6d3Kk= github.com/vearutop/dynhist-go v1.2.3 h1:EIMWszSDm6b7zmqySgx8zW2qNctE3IXUJggGlDFwJBE= github.com/vearutop/dynhist-go v1.2.3/go.mod h1:liiiYiwAi8ixC3DbkxooEhASTF6ysJSXy+piCrBtxEg= github.com/vearutop/gooselite v0.1.1 h1:C2CoI2Attj63yNsaEug9OVPRM5eeJlzqlZIbq4Za+Ok= @@ -483,20 +365,47 @@ github.com/yudai/gojsondiff v1.0.0 h1:27cbfqXLVEJ1o8I6v3y9lg8Ydm53EKqHXAOMxEGlCO github.com/yudai/gojsondiff v1.0.0/go.mod h1:AY32+k2cwILAkW1fbgxQ5mUmMiZFgLIV+FBNExI05xg= github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82 h1:BHyfKlQyqbsFN5p3IfnEUduWvb9is428/nNb5L3U01M= github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82/go.mod h1:lgjkn3NuSvDfVJdfcVVdX+jpBxNmX4rDAzaS45IcYoM= -github.com/yudai/pp v2.0.1+incompatible h1:Q4//iY4pNF6yPLZIigmvcl7k/bPgrcTPIFIcmawg5bI= -github.com/yudai/pp v2.0.1+incompatible/go.mod h1:PuxR/8QJ7cyCkFp/aUDS+JY727OFEZkTdatxwunjIkc= -github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= -go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= -go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= -go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= -go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= -go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= -go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= +go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64= +go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y= +go.opentelemetry.io/contrib/bridges/otelslog v0.18.0 h1:hhPGP3zvvy1xWT9RTy970wlniSxFttBIsAK1gvMguJM= +go.opentelemetry.io/contrib/bridges/otelslog v0.18.0/go.mod h1:twJF7inoMza6kxMcF8JOdL3mPmtOZu7GEr34CUNE6Dg= +go.opentelemetry.io/contrib/bridges/prometheus v0.68.0 h1:w3zlHYETbDwXyWHZlyyR58ZC39XGi8rAhkBgUgJ9d5w= +go.opentelemetry.io/contrib/bridges/prometheus v0.68.0/go.mod h1:GR/mClR2nn7vE8RLwxKjoBNg+QtgdDhRzxVa93koy5o= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.68.0 h1:CqXxU8VOmDefoh0+ztfGaymYbhdB/tT3zs79QaZTNGY= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.68.0/go.mod h1:BuhAPThV8PBHBvg8ZzZ/Ok3idOdhWIodywz2xEcRbJo= +go.opentelemetry.io/contrib/zpages v0.68.0 h1:H5yrUwxPrbvhzdBxjQD+VXMtPjIBfp8NWNVvQT8E30M= +go.opentelemetry.io/contrib/zpages v0.68.0/go.mod h1:sZGctYYO4UOHItj9bx3F+t/s+u1Fv8CHCJ5s2eR2cjU= +go.opentelemetry.io/otel v1.43.0 h1:mYIM03dnh5zfN7HautFE4ieIig9amkNANT+xcVxAj9I= +go.opentelemetry.io/otel v1.43.0/go.mod h1:JuG+u74mvjvcm8vj8pI5XiHy1zDeoCS2LB1spIq7Ay0= +go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.19.0 h1:HIBTQ3VO5aupLKjC90JgMqpezVXwFuq6Ryjn0/izoag= +go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.19.0/go.mod h1:ji9vId85hMxqfvICA0Jt8JqEdrXaAkcpkI9HPXya0ro= +go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.43.0 h1:w1K+pCJoPpQifuVpsKamUdn9U0zM3xUziVOqsGksUrY= +go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.43.0/go.mod h1:HBy4BjzgVE8139ieRI75oXm3EcDN+6GhD88JT1Kjvxg= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.43.0 h1:88Y4s2C8oTui1LGM6bTWkw0ICGcOLCAI5l6zsD1j20k= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.43.0/go.mod h1:Vl1/iaggsuRlrHf/hfPJPvVag77kKyvrLeD10kpMl+A= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.43.0 h1:3iZJKlCZufyRzPzlQhUIWVmfltrXuGyfjREgGP3UUjc= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.43.0/go.mod h1:/G+nUPfhq2e+qiXMGxMwumDrP5jtzU+mWN7/sjT2rak= +go.opentelemetry.io/otel/exporters/prometheus v0.65.0 h1:jOveH/b4lU9HT7y+Gfamf18BqlOuz2PWEvs8yM7Q6XE= +go.opentelemetry.io/otel/exporters/prometheus v0.65.0/go.mod h1:i1P8pcumauPtUI4YNopea1dhzEMuEqWP1xoUZDylLHo= +go.opentelemetry.io/otel/log v0.19.0 h1:KUZs/GOsw79TBBMfDWsXS+KZ4g2Ckzksd1ymzsIEbo4= +go.opentelemetry.io/otel/log v0.19.0/go.mod h1:5DQYeGmxVIr4n0/BcJvF4upsraHjg6vudJJpnkL6Ipk= +go.opentelemetry.io/otel/metric v1.43.0 h1:d7638QeInOnuwOONPp4JAOGfbCEpYb+K6DVWvdxGzgM= +go.opentelemetry.io/otel/metric v1.43.0/go.mod h1:RDnPtIxvqlgO8GRW18W6Z/4P462ldprJtfxHxyKd2PY= +go.opentelemetry.io/otel/sdk v1.43.0 h1:pi5mE86i5rTeLXqoF/hhiBtUNcrAGHLKQdhg4h4V9Dg= +go.opentelemetry.io/otel/sdk v1.43.0/go.mod h1:P+IkVU3iWukmiit/Yf9AWvpyRDlUeBaRg6Y+C58QHzg= +go.opentelemetry.io/otel/sdk/log v0.19.0 h1:scYVLqT22D2gqXItnWiocLUKGH9yvkkeql5dBDiXyko= +go.opentelemetry.io/otel/sdk/log v0.19.0/go.mod h1:vFBowwXGLlW9AvpuF7bMgnNI95LiW10szrOdvzBHlAg= +go.opentelemetry.io/otel/sdk/log/logtest v0.19.0 h1:BEbF7ZBB6qQloV/Ub1+3NQoOUnVtcGkU3XX4Ws3GQfk= +go.opentelemetry.io/otel/sdk/log/logtest v0.19.0/go.mod h1:Lua81/3yM0wOmoHTokLj9y9ADeA02v1naRrVrkAZuKk= +go.opentelemetry.io/otel/sdk/metric v1.43.0 h1:S88dyqXjJkuBNLeMcVPRFXpRw2fuwdvfCGLEo89fDkw= +go.opentelemetry.io/otel/sdk/metric v1.43.0/go.mod h1:C/RJtwSEJ5hzTiUz5pXF1kILHStzb9zFlIEe85bhj6A= +go.opentelemetry.io/otel/trace v1.43.0 h1:BkNrHpup+4k4w+ZZ86CZoHHEkohws8AY+WTX09nk+3A= +go.opentelemetry.io/otel/trace v1.43.0/go.mod h1:/QJhyVBUUswCphDVxq+8mld+AvhXZLhe+8WVFxiFff0= +go.opentelemetry.io/proto/otlp v1.10.0 h1:IQRWgT5srOCYfiWnpqUYz9CVmbO8bFmKcwYxpuCSL2g= +go.opentelemetry.io/proto/otlp v1.10.0/go.mod h1:/CV4QoCR/S9yaPj8utp3lvQPoqMtxXdzn7ozvvozVqk= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= @@ -504,25 +413,24 @@ go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/ 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.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= -go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8= -go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= +go.uber.org/zap v1.28.0 h1:IZzaP1Fv73/T/pBMLk4VutPl36uNC+OSUh3JLG3FIjo= +go.uber.org/zap v1.28.0/go.mod h1:rDLpOi171uODNm/mxFcuYWxDsqWSAVkFdX4XojSKg/Q= +go.yaml.in/yaml/v2 v2.4.4 h1:tuyd0P+2Ont/d6e2rl3be67goVK4R6deVxCUX5vyPaQ= +go.yaml.in/yaml/v2 v2.4.4/go.mod h1:gMZqIpDtDqOfM0uNfy0SkpRhvUryYH0Z6wdMYcacYXQ= +go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc= +go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= -golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= -golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= -golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= -golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= -golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= +golang.org/x/exp v0.0.0-20251023183803-a4bb9ffd2546 h1:mgKeJMpvi0yx/sU5GsxQ7p6s2wtOnGAHZWCHUM4KGzY= +golang.org/x/exp v0.0.0-20251023183803-a4bb9ffd2546/go.mod h1:j/pmGrbnkbPtQfxEe5D0VQhZC6qKbfKifgD0oM7sR70= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= @@ -532,17 +440,10 @@ golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHl golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= -golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= -golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= -golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= -golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/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-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -556,49 +457,17 @@ golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= -golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/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-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= -golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= -golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= -golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= -golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= -golang.org/x/net v0.35.0 h1:T5GQRQb2y08kTAByq9L4/bz8cipCdA8FbRTXewonqY8= -golang.org/x/net v0.35.0/go.mod h1:EglIi67kWsHKlRzzVMUD93VMSWGFOMSZgxFjparz1Qk= +golang.org/x/net v0.52.0 h1:He/TN1l0e4mmR3QqHMT2Xab3Aj3L9qjbhRm78/6jrW0= +golang.org/x/net v0.52.0/go.mod h1:R1MAz7uMZxVMualyPXb+VaqGSa3LIaUqk0eEt3w36Sw= 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= -golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.11.0 h1:GGz8+XQP4FvTTrjZPzNKTMFtSXH80RAzG+5ghFPgK9w= -golang.org/x/sync v0.11.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -608,57 +477,19 @@ golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/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-20220708085239-5a0f0661e09d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc= -golang.org/x/sys v0.30.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= +golang.org/x/sys v0.42.0 h1:omrd2nAlyT5ESRdCLYdm3+fMfNFE/+Rf4bDIQImRJeo= +golang.org/x/sys v0.42.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= -golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.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.22.0 h1:bofq7m3/HAFvbF51jz3Q9wLg3jkvSPuiZu/pD1XwgtM= -golang.org/x/text v0.22.0/go.mod h1:YRoo4H8PVmsu+E3Ou7cqLVH8oXWIHVoX0jqUWALQhfY= +golang.org/x/text v0.35.0 h1:JOVx6vVDFokkpaq1AEptVzLTpDe9KGpj5tR4/X+ybL8= +golang.org/x/text v0.35.0/go.mod h1:khi/HExzZJ2pGnjenulevKNX1W67CUy0AsXcNubPGCA= 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= golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 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= @@ -669,7 +500,6 @@ golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3 golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= @@ -677,59 +507,18 @@ golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtn golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= -golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= -golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= -golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= -golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= -golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= 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= +gonum.org/v1/gonum v0.17.0 h1:VbpOemQlsSMrYmn7T2OUvQ4dqxQXU+ouZFQsZOx50z4= +gonum.org/v1/gonum v0.17.0/go.mod h1:El3tOrEuMpv2UdMrbNlKEh9vd86bmQ6vqIcDwxEOc1E= google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= -google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= -google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= -google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= -google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= -google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM= -google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc= -google.golang.org/api v0.221.0 h1:qzaJfLhDsbMeFee8zBRdt/Nc+xmOuafD/dbdgGfutOU= -google.golang.org/api v0.221.0/go.mod h1:7sOU2+TL4TxUTdbi0gWgAIg7tH5qBXxoyhtL+9x3biQ= 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/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= -google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= -google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= @@ -739,59 +528,17 @@ google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98 google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA= -google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U= -google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= -google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= -google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto/googleapis/rpc v0.0.0-20250212204824-5a70512c5d8b h1:FQtJ1MxbXoIIrZHZ33M+w5+dAP9o86rgpjoKr/ZmT7k= -google.golang.org/genproto/googleapis/rpc v0.0.0-20250212204824-5a70512c5d8b/go.mod h1:8BS3B93F/U1juMFq9+EDk+qOT5CO1R9IzXxG3PTqiRk= +google.golang.org/genproto/googleapis/api v0.0.0-20260414002931-afd174a4e478 h1:yQugLulqltosq0B/f8l4w9VryjV+N/5gcW0jQ3N8Qec= +google.golang.org/genproto/googleapis/api v0.0.0-20260414002931-afd174a4e478/go.mod h1:C6ADNqOxbgdUUeRTU+LCHDPB9ttAMCTff6auwCVa4uc= +google.golang.org/genproto/googleapis/rpc v0.0.0-20260414002931-afd174a4e478 h1:RmoJA1ujG+/lRGNfUnOMfhCy5EipVMyvUE+KNbPbTlw= +google.golang.org/genproto/googleapis/rpc v0.0.0-20260414002931-afd174a4e478/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= -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.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= -google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= -google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= -google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= -google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= -google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= -google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= -google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= -google.golang.org/grpc v1.70.0 h1:pWFv03aZoHzlRKHWicjsZytKAiYCtNS0dHbXnIdq7jQ= -google.golang.org/grpc v1.70.0/go.mod h1:ofIJqVKDXx/JiXrwr2IG4/zwdH9txy3IlF40RmcJSQw= -google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= -google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= -google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= -google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= -google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= -google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= -google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= -google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= -google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= -google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= -google.golang.org/protobuf v1.36.5 h1:tPhr+woSbjfYvY6/GPufUoYizxw1cF/yFoxJ2fmpwlM= -google.golang.org/protobuf v1.36.5/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= +google.golang.org/grpc v1.80.0 h1:Xr6m2WmWZLETvUNvIUmeD5OAagMw3FiKmMlTdViWsHM= +google.golang.org/grpc v1.80.0/go.mod h1:ho/dLnxwi3EDJA4Zghp7k2Ec1+c2jqup0bFkw07bwF4= +google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE= +google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= @@ -801,15 +548,11 @@ gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EV gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= -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.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= @@ -819,10 +562,13 @@ 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-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= -honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= -honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= +modernc.org/libc v1.67.6 h1:eVOQvpModVLKOdT+LvBPjdQqfrZq+pC39BygcT+E7OI= +modernc.org/libc v1.67.6/go.mod h1:JAhxUVlolfYDErnwiqaLvUqc8nfb2r6S6slAgZOnaiE= +modernc.org/mathutil v1.7.1 h1:GCZVGXdaN8gTqB1Mf/usp1Y/hSqgI2vAGGP4jZMCxOU= +modernc.org/mathutil v1.7.1/go.mod h1:4p5IwJITfppl0G4sUEDtCr4DthTaT47/N3aT6MhfgJg= +modernc.org/memory v1.11.0 h1:o4QC8aMQzmcwCK3t3Ux/ZHmwFPzE6hf2Y5LbkRs+hbI= +modernc.org/memory v1.11.0/go.mod h1:/JP4VbVC+K5sU2wZi9bHoq2MAkCnrt2r98UGeSK7Mjw= +modernc.org/sqlite v1.46.1 h1:eFJ2ShBLIEnUWlLy12raN0Z1plqmFX9Qe3rjQTKt6sU= +modernc.org/sqlite v1.46.1/go.mod h1:CzbrU2lSB1DKUusvwGz7rqEKIq+NUd8GWuBBZDs9/nA= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= -rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= -rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= diff --git a/graceful/switch.go b/graceful/switch.go index f82c402..489001f 100644 --- a/graceful/switch.go +++ b/graceful/switch.go @@ -66,14 +66,11 @@ func (s *Switch) waitForSignal(done chan error, timeout time.Duration) { active := make(map[string]struct{}) for name, fn := range s.tasks { - fn := fn - name := name - sem <- struct{}{} active[name] = struct{}{} - go func() { + go func(name string, fn func()) { defer func() { s.mu.Lock() delete(active, name) @@ -82,7 +79,7 @@ func (s *Switch) waitForSignal(done chan error, timeout time.Duration) { }() fn() - }() + }(name, fn) } s.mu.Unlock() @@ -92,7 +89,7 @@ func (s *Switch) waitForSignal(done chan error, timeout time.Duration) { select { case sem <- struct{}{}: case <-deadline: - var err ErrTimeout + err := make(ErrTimeout, 0, len(active)) s.mu.Lock() diff --git a/http.go b/http.go index c5aaf45..cd02799 100644 --- a/http.go +++ b/http.go @@ -8,6 +8,7 @@ import ( "net/http" "time" + "github.com/bool64/brick/telemetry" "github.com/bool64/prom-stats" "github.com/prometheus/client_golang/prometheus/promhttp" "github.com/swaggest/openapi-go/openapi3" @@ -25,7 +26,7 @@ func NewBaseWebService(l *BaseLocator) *web.Service { r.Wrap(l.HTTPServerMiddlewares...) if pt, ok := l.StatsTracker().(*prom.Tracker); ok { - r.Method(http.MethodGet, "/metrics", promhttp.HandlerFor(pt.PrometheusRegistry(), promhttp.HandlerOpts{})) + r.Method(http.MethodGet, "/metrics", promhttp.HandlerFor(telemetry.PrometheusGatherer(pt.PrometheusRegistry()), promhttp.HandlerOpts{})) } if l.BaseConfig.Debug.DevTools { @@ -63,7 +64,7 @@ func (l *BaseLocator) StartHTTPServer(handler http.Handler) (string, error) { cfg.HTTPListenAddr = "127.0.0.1:0" } - listener, err := net.Listen("tcp", cfg.HTTPListenAddr) + listener, err := new(net.ListenConfig).Listen(context.Background(), "tcp", cfg.HTTPListenAddr) if err != nil { return "", fmt.Errorf("failed to start http server: %w", err) } diff --git a/init.go b/init.go index 1e327df..52e7ddd 100644 --- a/init.go +++ b/init.go @@ -1,13 +1,9 @@ package brick import ( - "time" - - ocprom "contrib.go.opencensus.io/exporter/prometheus" - "contrib.go.opencensus.io/integrations/ocsql" "github.com/bool64/brick/graceful" "github.com/bool64/brick/log" - "github.com/bool64/brick/opencensus" + "github.com/bool64/brick/telemetry" ucase "github.com/bool64/brick/usecase" "github.com/bool64/cache" "github.com/bool64/ctxd" @@ -24,8 +20,6 @@ import ( "github.com/swaggest/rest/openapi" "github.com/swaggest/rest/web" "github.com/swaggest/usecase" - "go.opencensus.io/stats/view" - "go.opencensus.io/trace" ) // NoOpLocator creates a dummy service locator, suitable to docs rendering. @@ -70,23 +64,22 @@ func NewBaseLocator(cfg BaseConfig) (*BaseLocator, error) { l.Switch = graceful.NewSwitch(cfg.ShutdownTimeout) - l.LoggerProvider = ctxz.NewObserver(zapctxd.New(cfg.Log).SkipCaller(), logz.Config{ + tel, err := setupTelemetry(l) + if err != nil { + return l, err + } + + l.LoggerProvider = ctxz.NewObserver(zapctxd.New(cfg.Log, tel.LoggerOptions...).SkipCaller(), logz.Config{ MaxCardinality: 100, MaxSamples: 50, }) l.UseCaseMiddlewares = []usecase.Middleware{ - opencensus.UseCaseMiddleware{}, + telemetry.UseCaseMiddleware{}, ucase.StatsMiddleware(l.StatsTracker()), log.UsecaseErrors(l.CtxdLogger()), } - if cfg.Debug.TraceSamplingProbability > 0 { - trace.ApplyConfig(trace.Config{ - DefaultSampler: trace.ProbabilitySampler(cfg.Debug.TraceSamplingProbability), - }) - } - l.HTTPRecoveryMiddleware = log.HTTPRecover{ // Panic recovery and request logging. Logger: l.CtxdLogger(), FieldNames: l.BaseConfig.Log.FieldNames, @@ -99,7 +92,7 @@ func NewBaseLocator(cfg BaseConfig) (*BaseLocator, error) { }) l.HTTPServerMiddlewares = append(l.HTTPServerMiddlewares, - opencensus.Middleware, // Tracing. + telemetry.Middleware, // Tracing and metrics. log.HTTPTraceTransaction(l.BaseConfig.Log.FieldNames), // Trace transaction. nethttp.UseCaseMiddlewares(l.UseCaseMiddlewares...), // Use case middlewares. ) @@ -114,9 +107,21 @@ func NewBaseLocator(cfg BaseConfig) (*BaseLocator, error) { return l, err } + l.DebugRouter = newDebugRouter(l, tel.TracezProcessor) + return l, nil } +func setupTelemetry(l *BaseLocator) (telemetry.SetupResult, error) { + return telemetry.Setup(telemetry.SetupParams{ + ServiceName: l.BaseConfig.ServiceName, + Environment: l.BaseConfig.Environment, + SamplingProbability: l.BaseConfig.Debug.TraceSamplingProbability, + Config: l.BaseConfig.Telemetry, + OnShutdown: l.OnShutdown, + }) +} + func setupPrometheus(l *BaseLocator) error { promReg := prometheus.NewRegistry() @@ -128,32 +133,14 @@ func setupPrometheus(l *BaseLocator) error { return err } - if err := view.Register(opencensus.Views()...); err != nil { + if err := telemetry.SetupMetrics(telemetry.MetricsParams{ + Config: l.BaseConfig.Telemetry, + Gatherer: promReg, + OnShutdown: l.OnShutdown, + }); err != nil { return err } - if err := view.Register(ocsql.DefaultViews...); err != nil { - return err - } - - // Initialize opencensus prometheus exporter. - promExporter, err := ocprom.NewExporter(ocprom.Options{ - Registry: promReg, - }) - if err != nil { - return err - } - - view.RegisterExporter(promExporter) - - l.OnShutdown("unregister_oc_prom", func() { - view.Unregister(opencensus.Views()...) - view.Unregister(ocsql.DefaultViews...) - view.UnregisterExporter(promExporter) - }) - - view.SetReportingPeriod(time.Second) - pt, err := prom.NewStatsTracker(promReg) if err != nil { return err diff --git a/init_test.go b/init_test.go index ff44852..26685d5 100644 --- a/init_test.go +++ b/init_test.go @@ -55,7 +55,7 @@ func TestNewBaseLocator(t *testing.T) { r := brick.NewBaseWebService(l) serviceURLPrefix := "/" + cfg.ServiceName - uc := usecase.NewIOI(nil, nil, func(_ context.Context, _, _ interface{}) error { + uc := usecase.NewIOI(nil, nil, func(_ context.Context, _, _ any) error { panic("oops") }) diff --git a/jaeger/setup.go b/jaeger/setup.go deleted file mode 100644 index 2e4e20a..0000000 --- a/jaeger/setup.go +++ /dev/null @@ -1,94 +0,0 @@ -// Package jaeger configures OpenCensus Jaeger exporter. -package jaeger - -import ( - "context" - "fmt" - - "contrib.go.opencensus.io/exporter/jaeger" - "github.com/bool64/ctxd" - "go.opencensus.io/trace" -) - -type deps interface { - CtxdLogger() ctxd.Logger - OnShutdown(name string, fn func()) -} - -// Config defines Jaeger settings. -type Config struct { - // CollectorEndpoint is the full url to the Jaeger HTTP Thrift collector. - // For example, http://localhost:14268/api/traces - CollectorEndpoint string `split_words:"true"` - - // AgentEndpoint instructs exporter to send spans to jaeger-agent at this address. - // For example, localhost:6831. - AgentEndpoint string `split_words:"true"` - - // OnError is the hook to be called when there is - // an error occurred when uploading the stats data. - // If no custom hook is set, errors are logged. - // Optional. - OnError func(err error) `json:"-"` - - // Username to be used if basic auth is required. - // Optional. - Username string - - // Password to be used if basic auth is required. - // Optional. - Password string - - // ServiceName is the Jaeger service name. - ServiceName string `split_words:"true"` - - // Tags are added to Jaeger Process exports. - Tags []jaeger.Tag - - // BufferMaxCount defines the total number of traces that can be buffered in memory. - BufferMaxCount int `split_words:"true"` -} - -// Setup configures Jaeger Exporter for OpenCensus traces. -// -// Add Jaeger to service configuration: -// -// Jaeger jaeger.Config `split_words:"true"` -func Setup(cfg Config, l deps) error { - if cfg.AgentEndpoint == "" && cfg.CollectorEndpoint == "" { - l.CtxdLogger().Info(context.Background(), "skipping jaeger setup") - - return nil - } - - opt := jaeger.Options{} - opt.CollectorEndpoint = cfg.CollectorEndpoint - opt.AgentEndpoint = cfg.AgentEndpoint - opt.Username = cfg.Username - opt.Password = cfg.Password - opt.Process.ServiceName = cfg.ServiceName - opt.Process.Tags = cfg.Tags - opt.BufferMaxCount = cfg.BufferMaxCount - opt.OnError = cfg.OnError - - l.CtxdLogger().Info(context.Background(), "setting up jaeger") - - cfg.OnError = func(err error) { - l.CtxdLogger().Error(context.Background(), "jaeger exporter failed", - "msg", err.Error(), - "type", fmt.Sprintf("%T", err), - "error", err) - } - - jaegerExporter, err := jaeger.NewExporter(opt) - if err != nil { - return err - } - - trace.RegisterExporter(jaegerExporter) - l.OnShutdown("unregister_oc_jaeger", func() { - trace.UnregisterExporter(jaegerExporter) - }) - - return nil -} diff --git a/log/http.go b/log/http.go index e1e36fc..8969118 100644 --- a/log/http.go +++ b/log/http.go @@ -3,6 +3,7 @@ package log import ( "context" "encoding/json" + "errors" "net/http" "runtime/debug" "strings" @@ -11,18 +12,25 @@ import ( "github.com/bool64/ctxd" "github.com/go-chi/chi/v5/middleware" "github.com/swaggest/rest" - "go.opencensus.io/trace" + "go.opentelemetry.io/otel/trace" ) // HTTPTraceTransaction adds trace transaction info to request context. func HTTPTraceTransaction(fields ctxd.FieldNames) func(h http.Handler) http.Handler { return func(h http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - if span := trace.FromContext(r.Context()); span != nil { + span := trace.SpanFromContext(r.Context()) + if span != nil { sc := span.SpanContext() + if !sc.IsValid() { + h.ServeHTTP(w, r) + + return + } + ctx := ctxd.AddFields(r.Context(), - fields.TraceID, sc.TraceID.String(), - fields.TransactionID, sc.SpanID.String(), + fields.TraceID, sc.TraceID().String(), + fields.TransactionID, sc.SpanID().String(), ) r = r.WithContext(ctx) } @@ -53,10 +61,10 @@ type HTTPRecover struct { FieldNames ctxd.FieldNames PrintPanic bool ExposePanic bool - OnPanic []func(ctx context.Context, rcv interface{}, stack []byte) + OnPanic []func(ctx context.Context, rcv any, stack []byte) } -func (mw HTTPRecover) handlePanic(ctx context.Context, rvr interface{}, msg string) { +func (mw HTTPRecover) handlePanic(ctx context.Context, rvr any, msg string) { if !mw.PrintPanic { mw.Logger.Error(ctx, msg, "panic", rvr, @@ -67,7 +75,7 @@ func (mw HTTPRecover) handlePanic(ctx context.Context, rvr interface{}, msg stri } } -func (mw HTTPRecover) processPanic(ctx context.Context, rvr interface{}, rw http.ResponseWriter) { +func (mw HTTPRecover) processPanic(ctx context.Context, rvr any, rw http.ResponseWriter) { mw.handlePanic(ctx, rvr, "request panicked") resp := rest.ErrResponse{ErrorText: "request panicked"} @@ -77,7 +85,7 @@ func (mw HTTPRecover) processPanic(ctx context.Context, rvr interface{}, rw http if mw.ExposePanic { stack = debug.Stack() - resp.Context = map[string]interface{}{ + resp.Context = map[string]any{ "panic": rvr, "stack": strings.Split(string(stack), "\n"), } } @@ -116,8 +124,11 @@ func (mw HTTPRecover) Middleware() func(handler http.Handler) http.Handler { defer func() { rvr := recover() - //nolint:errorlint,goerr113 // Panic with sentinel error is not wrapped. - if rvr == nil || rvr == http.ErrAbortHandler { + if rvr == nil { + return + } + + if err, ok := rvr.(error); ok && errors.Is(err, http.ErrAbortHandler) { return } @@ -155,7 +166,7 @@ func (mw HTTPRecover) Middleware() func(handler http.Handler) http.Handler { } func headersMap(header http.Header) ctxd.DeferredJSON { - return func() interface{} { + return func() any { headers := make(map[string]string, len(header)) for k := range header { diff --git a/log/trace.go b/log/trace.go index 902f293..cfbe42e 100644 --- a/log/trace.go +++ b/log/trace.go @@ -4,26 +4,32 @@ import ( "context" "github.com/bool64/ctxd" - "go.opencensus.io/trace" + "go.opentelemetry.io/otel/trace" + "go.opentelemetry.io/otel/trace/embedded" ) type tracerWithLog struct { + embedded.Tracer field string - trace.Tracer + next trace.Tracer } -func (t *tracerWithLog) NewContext(parent context.Context, s *trace.Span) context.Context { - ctx := t.Tracer.NewContext(parent, s) - sc := s.SpanContext() +func (t *tracerWithLog) Start(ctx context.Context, spanName string, opts ...trace.SpanStartOption) (context.Context, trace.Span) { + ctx, span := t.next.Start(ctx, spanName, opts...) + sc := span.SpanContext() - return ctxd.SetFields(ctx, t.field, sc.SpanID) + if !sc.IsValid() { + return ctx, span + } + + return ctxd.SetFields(ctx, t.field, sc.SpanID().String()), span } -// SpanIDFieldToContexts instruments trace.Tracer to add SpanID to context fields. +// SpanIDFieldToContexts instruments trace.Tracer to add span ID to context fields. func SpanIDFieldToContexts(fieldName string, tracer trace.Tracer) trace.Tracer { if _, ok := tracer.(*tracerWithLog); ok { return tracer } - return &tracerWithLog{Tracer: tracer, field: fieldName} + return &tracerWithLog{next: tracer, field: fieldName} } diff --git a/log/usecase.go b/log/usecase.go index e8b6551..e5651df 100644 --- a/log/usecase.go +++ b/log/usecase.go @@ -33,7 +33,7 @@ func UsecaseErrors(logger ctxd.Logger) usecase.Middleware { name = "unnamed" + strconv.Itoa(unknownIndex) } - return usecase.Interact(func(ctx context.Context, input, output interface{}) error { + return usecase.Interact(func(ctx context.Context, input, output any) error { err := u.Interact(ctx, input, output) if err != nil { logger.Error(ctx, "usecase failed", "error", err, "name", name) diff --git a/opencensus/doc.go b/opencensus/doc.go deleted file mode 100644 index c5e4863..0000000 --- a/opencensus/doc.go +++ /dev/null @@ -1,2 +0,0 @@ -// Package opencensus provides helpers for OpenCensus instrumentation. -package opencensus diff --git a/opencensus/http.go b/opencensus/http.go deleted file mode 100644 index 0224b08..0000000 --- a/opencensus/http.go +++ /dev/null @@ -1,30 +0,0 @@ -package opencensus - -import ( - "net/http" - - "github.com/swaggest/rest" - "github.com/swaggest/rest/nethttp" - "go.opencensus.io/plugin/ochttp" -) - -// Middleware instruments router with OpenCensus metrics. -func Middleware(handler http.Handler) http.Handler { - var withRoute rest.HandlerWithRoute - - if nethttp.HandlerAs(handler, &withRoute) { - method := withRoute.RouteMethod() - pattern := withRoute.RoutePattern() - - return ochttp.WithRouteTag(&ochttp.Handler{ - FormatSpanName: func(_ *http.Request) string { - return method + " " + pattern - }, - Handler: handler, - }, method+pattern) - } - - return &ochttp.Handler{ - Handler: handler, - } -} diff --git a/opencensus/span.go b/opencensus/span.go deleted file mode 100644 index a17ce6d..0000000 --- a/opencensus/span.go +++ /dev/null @@ -1,44 +0,0 @@ -package opencensus - -import ( - "context" - "errors" - - "github.com/bool64/brick/runtime" - "github.com/swaggest/usecase/status" - "go.opencensus.io/trace" -) - -// AddSpan starts OpenCensus trace span and returns updated context with callback to finish span. -// -// Span is named by the parent function. -// Typically, span should be finished with deferred statement. -// -// var err error -// ctx, finish := opencensus.AddSpan(ctx, -// trace.StringAttribute("key", "value"), -// ) -// defer finish(&err) -func AddSpan(ctx context.Context, attributes ...trace.Attribute) (context.Context, func(*error)) { - ctx, span := trace.StartSpan(ctx, runtime.CallerFunc(2)) //nolint:spancheck - span.AddAttributes(attributes...) - - return ctx, func(err *error) { //nolint:spancheck - if err != nil && *err != nil { - e := *err - st := status.Unknown - - var ws errorWithStatus - if errors.As(e, &ws) { - st = ws.Status() - } - - span.SetStatus(trace.Status{ - Code: int32(st), - Message: e.Error(), - }) - } - - span.End() - } -} diff --git a/opencensus/views.go b/opencensus/views.go deleted file mode 100644 index 137c0b3..0000000 --- a/opencensus/views.go +++ /dev/null @@ -1,85 +0,0 @@ -package opencensus - -import ( - "go.opencensus.io/plugin/ochttp" - "go.opencensus.io/stats/view" - "go.opencensus.io/tag" -) - -// Views lists OpenCensus views rendered as metrics. -func Views() []*view.View { //nolint:funlen - return []*view.View{ - { - Name: "http/server/request_count", - Description: "Count of HTTP requests started", - Measure: ochttp.ServerRequestCount, - Aggregation: view.Count(), - }, - { - Name: "http/server/request_bytes", - Description: "Size distribution of HTTP request body", - Measure: ochttp.ServerRequestBytes, - Aggregation: ochttp.DefaultSizeDistribution, - }, - { - Name: "http/server/response_bytes", - Description: "Size distribution of HTTP response body", - Measure: ochttp.ServerResponseBytes, - Aggregation: ochttp.DefaultSizeDistribution, - }, - { - Name: "http/server/latency", - Description: "Latency distribution of HTTP requests", - Measure: ochttp.ServerLatency, - Aggregation: ochttp.DefaultLatencyDistribution, - }, - { - Name: "http/server/request_count_by_method", - Description: "Server request count by HTTP method", - TagKeys: []tag.Key{ochttp.Method}, - Measure: ochttp.ServerRequestCount, - Aggregation: view.Count(), - }, - { - Name: "http/server/response_count_by_status_code", - Description: "Server response count by status code", - TagKeys: []tag.Key{ochttp.StatusCode}, - Measure: ochttp.ServerLatency, - Aggregation: view.Count(), - }, - { - Name: "http/server/latency_by_path", - Description: "Latency distribution of HTTP requests by route", - TagKeys: []tag.Key{ochttp.KeyServerRoute}, - Measure: ochttp.ServerLatency, - Aggregation: ochttp.DefaultLatencyDistribution, - }, - { - Name: "http/client/completed_count", - Measure: ochttp.ClientRoundtripLatency, - Aggregation: view.Count(), - Description: "Count of completed requests, by HTTP method and response status", - TagKeys: []tag.Key{ochttp.KeyClientHost, ochttp.KeyClientMethod, ochttp.KeyClientStatus}, - }, - { - Name: "http/client/sent_bytes", - Measure: ochttp.ClientSentBytes, - Aggregation: ochttp.DefaultSizeDistribution, - Description: "Total bytes sent in request body (not including headers), by HTTP method and response status", - TagKeys: []tag.Key{ochttp.KeyClientHost, ochttp.KeyClientMethod, ochttp.KeyClientStatus}, - }, - { - Name: "http/client/received_bytes", - Measure: ochttp.ClientReceivedBytes, - Aggregation: ochttp.DefaultSizeDistribution, - Description: "Total bytes received in response bodies (not including headers but including error responses with bodies), by HTTP method and response status", - TagKeys: []tag.Key{ochttp.KeyClientHost, ochttp.KeyClientMethod, ochttp.KeyClientStatus}, - }, - { - Name: "http/client/latency_by_host", - TagKeys: []tag.Key{ochttp.KeyClientHost}, - Measure: ochttp.ClientRoundtripLatency, - Aggregation: ochttp.DefaultLatencyDistribution, - }, - } -} diff --git a/runtime/caller.go b/runtime/caller.go index 009d0c1..6eb8555 100644 --- a/runtime/caller.go +++ b/runtime/caller.go @@ -3,6 +3,7 @@ package runtime import ( "path" "runtime" + "slices" "strings" ) @@ -38,17 +39,7 @@ func Ancestor(skipCallers, stackSize int, skipPackages ...string) string { parts[len(parts)-1] = strings.Split(parts[len(parts)-1], ".")[0] p = strings.Join(parts, "/") - skip := false - - for _, sp := range skipPackages { - if p == sp { - skip = true - - break - } - } - - if skip { + if slices.Contains(skipPackages, p) { continue } diff --git a/runtime/heap.go b/runtime/heap.go index 9ceb3a8..e2bda5b 100644 --- a/runtime/heap.go +++ b/runtime/heap.go @@ -31,5 +31,9 @@ func StableHeapInUse() int64 { runtime.GC() } + if m.HeapInuse > math.MaxInt64 { + return math.MaxInt64 + } + return int64(m.HeapInuse) } diff --git a/telemetry/config.go b/telemetry/config.go new file mode 100644 index 0000000..f1be120 --- /dev/null +++ b/telemetry/config.go @@ -0,0 +1,102 @@ +package telemetry + +import ( + "encoding/base64" + "strings" + "time" +) + +// Config configures OpenTelemetry export. +type Config struct { + // BaseURL is the OTLP gateway base URL. + // For Grafana Cloud this is typically https://otlp-gateway-.grafana.net/otlp. + BaseURL string `split_words:"true"` + + // TracesURL overrides traces export URL. + TracesURL string `split_words:"true"` + + // MetricsURL overrides metrics export URL. + MetricsURL string `split_words:"true"` + + // LogsURL overrides logs export URL. + LogsURL string `split_words:"true"` + + // Username is used to build Authorization header when Authorization is empty. + Username string `split_words:"true"` + + // Password is used to build Authorization header when Authorization is empty. + Password string `split_words:"true"` + + // Authorization sets the Authorization header directly. + Authorization string `split_words:"true"` + + // MetricsInterval configures periodic OTLP metrics export interval. + MetricsInterval time.Duration `split_words:"true" default:"15s"` +} + +// TraceEndpoint returns the OTLP traces endpoint URL. +func (c Config) TraceEndpoint() string { + if c.TracesURL != "" { + return c.TracesURL + } + + if c.BaseURL == "" { + return "" + } + + return strings.TrimRight(c.BaseURL, "/") + "/v1/traces" +} + +// MetricEndpoint returns the OTLP metrics endpoint URL. +func (c Config) MetricEndpoint() string { + if c.MetricsURL != "" { + return c.MetricsURL + } + + if c.BaseURL == "" { + return "" + } + + return strings.TrimRight(c.BaseURL, "/") + "/v1/metrics" +} + +// LogEndpoint returns the OTLP logs endpoint URL. +func (c Config) LogEndpoint() string { + if c.LogsURL != "" { + return c.LogsURL + } + + if c.BaseURL == "" { + return "" + } + + return strings.TrimRight(c.BaseURL, "/") + "/v1/logs" +} + +// AuthorizationHeader returns the Authorization header for OTLP requests. +func (c Config) AuthorizationHeader() string { + if c.Authorization != "" { + return c.Authorization + } + + if c.Username == "" && c.Password == "" { + return "" + } + + return "Basic " + base64.StdEncoding.EncodeToString([]byte(c.Username+":"+c.Password)) +} + +// Headers returns OTLP request headers derived from configuration. +func (c Config) Headers() map[string]string { + auth := c.AuthorizationHeader() + if auth == "" { + return nil + } + + return map[string]string{"Authorization": auth} +} + +// Enabled reports whether any remote telemetry export is configured. +func (c Config) Enabled() bool { + return c.TraceEndpoint() != "" || c.LogEndpoint() != "" || c.MetricEndpoint() != "" +} diff --git a/telemetry/config_test.go b/telemetry/config_test.go new file mode 100644 index 0000000..f4df489 --- /dev/null +++ b/telemetry/config_test.go @@ -0,0 +1,24 @@ +package telemetry_test + +import ( + "testing" + + "github.com/bool64/brick/telemetry" + "github.com/stretchr/testify/assert" +) + +func TestConfig_GrafanaStyleDefaults(t *testing.T) { + cfg := telemetry.Config{ + BaseURL: "https://otlp-gateway-prod-eu-west-2.grafana.net/otlp", + Username: "12345", + Password: "glc_abcdef", + } + + assert.Equal(t, "https://otlp-gateway-prod-eu-west-2.grafana.net/otlp/v1/traces", cfg.TraceEndpoint()) + assert.Equal(t, "https://otlp-gateway-prod-eu-west-2.grafana.net/otlp/v1/metrics", cfg.MetricEndpoint()) + assert.Equal(t, "https://otlp-gateway-prod-eu-west-2.grafana.net/otlp/v1/logs", cfg.LogEndpoint()) + assert.Equal(t, "Basic MTIzNDU6Z2xjX2FiY2RlZg==", cfg.AuthorizationHeader()) + assert.Equal(t, map[string]string{ + "Authorization": "Basic MTIzNDU6Z2xjX2FiY2RlZg==", + }, cfg.Headers()) +} diff --git a/telemetry/doc.go b/telemetry/doc.go new file mode 100644 index 0000000..53638e6 --- /dev/null +++ b/telemetry/doc.go @@ -0,0 +1,2 @@ +// Package telemetry provides OpenTelemetry helpers. +package telemetry diff --git a/telemetry/http.go b/telemetry/http.go new file mode 100644 index 0000000..0a76431 --- /dev/null +++ b/telemetry/http.go @@ -0,0 +1,37 @@ +package telemetry + +import ( + "net/http" + + "github.com/swaggest/rest" + "github.com/swaggest/rest/nethttp" + "go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp" + "go.opentelemetry.io/otel/attribute" +) + +// Middleware instruments router with OpenTelemetry metrics and traces. +func Middleware(handler http.Handler) http.Handler { + var withRoute rest.HandlerWithRoute + + if nethttp.HandlerAs(handler, &withRoute) { + method := withRoute.RouteMethod() + pattern := withRoute.RoutePattern() + next := handler + + handler = http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) { + if labeler, ok := otelhttp.LabelerFromContext(req.Context()); ok { + labeler.Add(attribute.String("http.route", pattern)) + } + + next.ServeHTTP(rw, req) + }) + + return otelhttp.NewHandler(handler, method+" "+pattern, + otelhttp.WithSpanNameFormatter(func(_ string, _ *http.Request) string { + return method + " " + pattern + }), + ) + } + + return otelhttp.NewHandler(handler, "http.server") +} diff --git a/telemetry/metrics.go b/telemetry/metrics.go new file mode 100644 index 0000000..b9e1ef0 --- /dev/null +++ b/telemetry/metrics.go @@ -0,0 +1,121 @@ +package telemetry + +import ( + "context" + "fmt" + "sync" + "time" + + "github.com/prometheus/client_golang/prometheus" + bridgeprom "go.opentelemetry.io/contrib/bridges/prometheus" + "go.opentelemetry.io/otel" + "go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp" + otelprom "go.opentelemetry.io/otel/exporters/prometheus" + "go.opentelemetry.io/otel/sdk/metric" +) + +// MetricsParams configure metrics provider setup. +type MetricsParams struct { + Config Config + Gatherer prometheus.Gatherer + OnShutdown ShutdownRegistrar +} + +var ( + prometheusGathererMu sync.RWMutex + prometheusGatherer prometheus.Gatherer +) + +// PrometheusGatherer returns a gatherer that includes native Prometheus metrics and OTel metrics. +func PrometheusGatherer(native prometheus.Gatherer) prometheus.Gatherer { + prometheusGathererMu.RLock() + otelGatherer := prometheusGatherer + prometheusGathererMu.RUnlock() + + switch { + case native == nil: + return otelGatherer + case otelGatherer == nil: + return native + default: + return prometheus.Gatherers{native, otelGatherer} + } +} + +// SetupMetrics configures the global OTel meter provider with Prometheus and optional OTLP readers. +func SetupMetrics(p MetricsParams) error { + otelRegistry := prometheus.NewRegistry() + + promExporter, err := otelprom.New(otelprom.WithRegisterer(otelRegistry)) + if err != nil { + return err + } + + prometheusGathererMu.Lock() + prometheusGatherer = otelRegistry + prometheusGathererMu.Unlock() + + readers := []metric.Option{metric.WithReader(promExporter)} + + var producers []metric.Producer + + if p.Gatherer != nil { + producers = append(producers, bridgeprom.NewMetricProducer(bridgeprom.WithGatherer(p.Gatherer))) + } + + if reader, err := NewMetricsReader(p.Config, producers...); err != nil { + return err + } else if reader != nil { + readers = append(readers, metric.WithReader(reader)) + } + + meterProvider := metric.NewMeterProvider(readers...) + otel.SetMeterProvider(meterProvider) + + if p.OnShutdown != nil { + p.OnShutdown("otel_meter_provider", func() { + prometheusGathererMu.Lock() + prometheusGatherer = nil + prometheusGathererMu.Unlock() + + logShutdownError("otel meter provider", meterProvider.Shutdown(context.Background())) + }) + } + + return nil +} + +// NewMetricsReader creates an OTLP metrics reader if metrics export is configured. +func NewMetricsReader(cfg Config, producers ...metric.Producer) (metric.Reader, error) { + if cfg.MetricEndpoint() == "" { + return nil, nil + } + + opts := []otlpmetrichttp.Option{ + otlpmetrichttp.WithEndpointURL(cfg.MetricEndpoint()), + } + + if headers := cfg.Headers(); headers != nil { + opts = append(opts, otlpmetrichttp.WithHeaders(headers)) + } + + exporter, err := otlpmetrichttp.New(context.Background(), opts...) + if err != nil { + return nil, fmt.Errorf("init otlp metrics exporter: %w", err) + } + + interval := cfg.MetricsInterval + if interval <= 0 { + interval = 15 * time.Second + } + + readerOpts := []metric.PeriodicReaderOption{metric.WithInterval(interval)} + + for _, producer := range producers { + if producer != nil { + readerOpts = append(readerOpts, metric.WithProducer(producer)) + } + } + + return metric.NewPeriodicReader(exporter, readerOpts...), nil +} diff --git a/telemetry/otelzapcore.go b/telemetry/otelzapcore.go new file mode 100644 index 0000000..a65d09a --- /dev/null +++ b/telemetry/otelzapcore.go @@ -0,0 +1,100 @@ +package telemetry + +import ( + "context" + "log/slog" + + "go.uber.org/zap/zapcore" +) + +type otelZapCore struct { + handler slog.Handler + enabler zapcore.LevelEnabler + attrs []slog.Attr +} + +// NewZapCore creates a zap core that mirrors zap entries into a slog handler. +func NewZapCore(handler slog.Handler, enabler zapcore.LevelEnabler) zapcore.Core { + return &otelZapCore{ + handler: handler, + enabler: enabler, + } +} + +func (o *otelZapCore) Enabled(level zapcore.Level) bool { + return o.enabler.Enabled(level) +} + +func (o *otelZapCore) With(fields []zapcore.Field) zapcore.Core { + attrs := append([]slog.Attr{}, o.attrs...) + attrs = append(attrs, zapFieldsToAttrs(fields)...) + + return &otelZapCore{ + handler: o.handler, + enabler: o.enabler, + attrs: attrs, + } +} + +func (o *otelZapCore) Check(entry zapcore.Entry, checked *zapcore.CheckedEntry) *zapcore.CheckedEntry { + if o.Enabled(entry.Level) { + return checked.AddCore(entry, o) + } + + return checked +} + +func (o *otelZapCore) Write(entry zapcore.Entry, fields []zapcore.Field) error { + record := slog.NewRecord(entry.Time, zapLevelToSlog(entry.Level), entry.Message, 0) + record.AddAttrs(o.attrs...) + record.AddAttrs(zapFieldsToAttrs(fields)...) + + if entry.LoggerName != "" { + record.AddAttrs(slog.String("logger.name", entry.LoggerName)) + } + + if entry.Caller.Defined { + record.AddAttrs(slog.String("code.filepath", entry.Caller.TrimmedPath())) + } + + if entry.Stack != "" { + record.AddAttrs(slog.String("exception.stacktrace", entry.Stack)) + } + + return o.handler.Handle(context.Background(), record) +} + +func (o *otelZapCore) Sync() error { + return nil +} + +func zapLevelToSlog(level zapcore.Level) slog.Level { + switch { + case level <= zapcore.DebugLevel: + return slog.LevelDebug + case level <= zapcore.InfoLevel: + return slog.LevelInfo + case level <= zapcore.WarnLevel: + return slog.LevelWarn + default: + return slog.LevelError + } +} + +func zapFieldsToAttrs(fields []zapcore.Field) []slog.Attr { + if len(fields) == 0 { + return nil + } + + enc := zapcore.NewMapObjectEncoder() + for _, field := range fields { + field.AddTo(enc) + } + + attrs := make([]slog.Attr, 0, len(enc.Fields)) + for key, value := range enc.Fields { + attrs = append(attrs, slog.Any(key, value)) + } + + return attrs +} diff --git a/telemetry/setup.go b/telemetry/setup.go new file mode 100644 index 0000000..6924886 --- /dev/null +++ b/telemetry/setup.go @@ -0,0 +1,162 @@ +package telemetry + +import ( + "context" + "fmt" + "log/slog" + + "go.opentelemetry.io/contrib/bridges/otelslog" + "go.opentelemetry.io/contrib/zpages" + "go.opentelemetry.io/otel" + "go.opentelemetry.io/otel/attribute" + "go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp" + "go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp" + "go.opentelemetry.io/otel/propagation" + sdklog "go.opentelemetry.io/otel/sdk/log" + "go.opentelemetry.io/otel/sdk/resource" + sdktrace "go.opentelemetry.io/otel/sdk/trace" + "go.uber.org/zap" + "go.uber.org/zap/zapcore" +) + +// ShutdownRegistrar registers shutdown callbacks by name. +type ShutdownRegistrar func(name string, fn func()) + +// SetupParams configure telemetry bootstrap. +type SetupParams struct { + ServiceName string + Environment string + SamplingProbability float64 + Config Config + OnShutdown ShutdownRegistrar +} + +// SetupResult keeps initialized implementation details needed by callers. +type SetupResult struct { + TracezProcessor *zpages.SpanProcessor + LoggerOptions []zap.Option +} + +// Setup initializes global tracing and optional log export. +func Setup(p SetupParams) (SetupResult, error) { + res, err := resource.New(context.Background(), + resource.WithAttributes( + attribute.String("service.name", p.ServiceName), + attribute.String("deployment.environment", p.Environment), + ), + resource.WithTelemetrySDK(), + ) + if err != nil { + return SetupResult{}, err + } + + tracezProcessor := zpages.NewSpanProcessor() + options := []sdktrace.TracerProviderOption{ + sdktrace.WithResource(res), + sdktrace.WithSampler(sdktrace.ParentBased(sdktrace.TraceIDRatioBased(p.SamplingProbability))), + sdktrace.WithSpanProcessor(tracezProcessor), + } + + if exp, err := setupTraceExporter(p.Config); err != nil { + return SetupResult{}, err + } else if exp != nil { + options = append(options, sdktrace.WithBatcher(exp)) + } + + tracerProvider := sdktrace.NewTracerProvider(options...) + otel.SetTracerProvider(tracerProvider) + otel.SetTextMapPropagator(propagation.NewCompositeTextMapPropagator( + propagation.TraceContext{}, + propagation.Baggage{}, + )) + + if p.OnShutdown != nil { + p.OnShutdown("otel_tracer_provider", func() { + logShutdownError("otel tracer provider", tracerProvider.Shutdown(context.Background())) + }) + } + + logHandler, err := setupLogs(p.ServiceName, p.Config, res, p.OnShutdown) + if err != nil { + return SetupResult{}, err + } + + return SetupResult{ + TracezProcessor: tracezProcessor, + LoggerOptions: loggerOptions(logHandler), + }, nil +} + +func setupTraceExporter(cfg Config) (sdktrace.SpanExporter, error) { + if cfg.TraceEndpoint() == "" { + return nil, nil + } + + opts := []otlptracehttp.Option{ + otlptracehttp.WithEndpointURL(cfg.TraceEndpoint()), + } + + if headers := cfg.Headers(); headers != nil { + opts = append(opts, otlptracehttp.WithHeaders(headers)) + } + + exporter, err := otlptracehttp.New(context.Background(), opts...) + if err != nil { + return nil, fmt.Errorf("init otlp trace exporter: %w", err) + } + + return exporter, nil +} + +func setupLogs(serviceName string, cfg Config, res *resource.Resource, onShutdown ShutdownRegistrar) (slog.Handler, error) { + if cfg.LogEndpoint() == "" { + return nil, nil + } + + opts := []otlploghttp.Option{ + otlploghttp.WithEndpointURL(cfg.LogEndpoint()), + } + + if headers := cfg.Headers(); headers != nil { + opts = append(opts, otlploghttp.WithHeaders(headers)) + } + + exporter, err := otlploghttp.New(context.Background(), opts...) + if err != nil { + return nil, fmt.Errorf("init otlp log exporter: %w", err) + } + + loggerProvider := sdklog.NewLoggerProvider( + sdklog.WithResource(res), + sdklog.WithProcessor(sdklog.NewBatchProcessor(exporter)), + ) + logHandler := otelslog.NewHandler(serviceName, + otelslog.WithLoggerProvider(loggerProvider), + ) + + if onShutdown != nil { + onShutdown("otel_log_provider", func() { + logShutdownError("otel log provider", loggerProvider.Shutdown(context.Background())) + }) + } + + return logHandler, nil +} + +func loggerOptions(logHandler slog.Handler) []zap.Option { + if logHandler == nil { + return nil + } + + return []zap.Option{ + zap.WrapCore(func(core zapcore.Core) zapcore.Core { + return zapcore.NewTee(core, NewZapCore(logHandler, zap.DebugLevel)) + }), + } +} + +func logShutdownError(name string, err error) { + if err != nil { + slog.Default().Error("telemetry shutdown failed", "component", name, "error", err) + } +} diff --git a/telemetry/span.go b/telemetry/span.go new file mode 100644 index 0000000..e904abc --- /dev/null +++ b/telemetry/span.go @@ -0,0 +1,37 @@ +package telemetry + +import ( + "context" + + "github.com/bool64/brick/runtime" + "go.opentelemetry.io/otel" + "go.opentelemetry.io/otel/attribute" + "go.opentelemetry.io/otel/codes" +) + +// AddSpan starts OpenTelemetry span and returns updated context with callback to finish span. +// +// Span is named by the parent function. +// Typically, span should be finished with deferred statement. +// +// var err error +// ctx, finish := telemetry.AddSpan(ctx, +// attribute.String("key", "value"), +// ) +// defer finish(&err) +// +//nolint:spancheck // The returned callback owns span.End and must be deferred by the caller. +func AddSpan(ctx context.Context, attributes ...attribute.KeyValue) (context.Context, func(*error)) { + ctx, span := otel.Tracer("github.com/bool64/brick/telemetry").Start(ctx, runtime.CallerFunc(2)) + span.SetAttributes(attributes...) + + return ctx, func(err *error) { + if err != nil && *err != nil { + e := *err + span.SetStatus(codes.Error, e.Error()) + span.RecordError(e) + } + + span.End() + } +} diff --git a/opencensus/usecase.go b/telemetry/usecase.go similarity index 58% rename from opencensus/usecase.go rename to telemetry/usecase.go index e02d356..ccfa162 100644 --- a/opencensus/usecase.go +++ b/telemetry/usecase.go @@ -1,20 +1,16 @@ -package opencensus +package telemetry import ( "context" - "errors" "fmt" "github.com/swaggest/usecase" - "github.com/swaggest/usecase/status" - "go.opencensus.io/trace" + "go.opentelemetry.io/otel" + "go.opentelemetry.io/otel/attribute" + "go.opentelemetry.io/otel/codes" ) -type errorWithStatus interface { - Status() status.Code -} - -// UseCaseMiddleware is a tracing usecase middleware. +// UseCaseMiddleware is a tracing use case middleware. type UseCaseMiddleware struct { WithInput bool } @@ -37,27 +33,18 @@ func (mw UseCaseMiddleware) Wrap(u usecase.Interactor) usecase.Interactor { spanName = "useCaseUnknown" } - return usecase.Interact(func(ctx context.Context, input, output interface{}) error { - ctx, span := trace.StartSpan(ctx, spanName) + return usecase.Interact(func(ctx context.Context, input, output any) error { + ctx, span := otel.Tracer("github.com/bool64/brick/telemetry").Start(ctx, spanName) if mw.WithInput { - span.AddAttributes(trace.StringAttribute("input", fmt.Sprintf("%v", input))) + span.SetAttributes(attribute.String("input", fmt.Sprintf("%v", input))) } defer span.End() err := u.Interact(ctx, input, output) if err != nil { - st := status.Unknown - - var ws errorWithStatus - if errors.As(err, &ws) { - st = ws.Status() - } - - span.SetStatus(trace.Status{ - Code: int32(st), - Message: err.Error(), - }) + span.SetStatus(codes.Error, err.Error()) + span.RecordError(err) } return err diff --git a/test/feature.go b/test/feature.go index 7fb79b6..0f32119 100644 --- a/test/feature.go +++ b/test/feature.go @@ -53,7 +53,7 @@ func newContext(t *testing.T) *Context { tc.External.VS = vs tc.Database = dbsteps.NewManager() - tc.Database.Vars = vs.JSONComparer.Vars + tc.Database.VS.JSONComparer.Vars = vs.JSONComparer.Vars tc.VS = vs tc.Vars = vs.JSONComparer.Vars @@ -75,6 +75,18 @@ func RunFeatures(t *testing.T, envPrefix string, cfg brick.WithBaseConfig, init tc := newContext(t) l, router := init(tc) + requireFeatureServer(t, tc, l, router) + + suite := featureSuite(t, cfg, tc) + configureFeatureFormatters(&suite) + + assert.Equal(t, 0, suite.Run(), "non-zero status returned, failed to run feature tests") + shutdownFeatureServer(l) + <-l.Wait() +} + +func requireFeatureServer(t *testing.T, tc *Context, l *brick.BaseLocator, router http.Handler) { + t.Helper() addr, err := l.StartHTTPServer(router) require.NoError(t, err) @@ -84,6 +96,10 @@ func RunFeatures(t *testing.T, envPrefix string, cfg brick.WithBaseConfig, init dbi := tc.Database.Instances[dbsteps.Default] dbi.Storage = l.Storage tc.Database.Instances[dbsteps.Default] = dbi +} + +func featureSuite(t *testing.T, cfg brick.WithBaseConfig, tc *Context) godog.TestSuite { + t.Helper() godogx.RegisterPrettyFailedFormatter() @@ -101,7 +117,7 @@ func RunFeatures(t *testing.T, envPrefix string, cfg brick.WithBaseConfig, init tc.OptionsInitializer(&options) } - suite := godog.TestSuite{ + return godog.TestSuite{ Name: cfg.Base().ServiceName + "-integration-test", ScenarioInitializer: func(s *godog.ScenarioContext) { tc.Local.RegisterSteps(s) @@ -115,21 +131,21 @@ func RunFeatures(t *testing.T, envPrefix string, cfg brick.WithBaseConfig, init }, Options: &options, } +} +func configureFeatureFormatters(suite *godog.TestSuite) { if os.Getenv("GODOG_ALLURE") != "" { allure.RegisterFormatter() suite.Options.Format += ",allure" } +} - assert.Equal(t, 0, suite.Run(), "non-zero status returned, failed to run feature tests") - +func shutdownFeatureServer(l *brick.BaseLocator) { // An instance can keep on running if developer would like to use or debug it after tests have finished. if os.Getenv("GODOG_KEEP_INSTANCE") == "1" { println("tests passed, keeping instance, kill it manually at will") } else { l.Shutdown() } - - <-l.Wait() } diff --git a/usecase/stats.go b/usecase/stats.go index afdb22f..3738309 100644 --- a/usecase/stats.go +++ b/usecase/stats.go @@ -36,7 +36,7 @@ func StatsMiddleware(tracker stats.Tracker) usecase.Middleware { name = "unnamed" + strconv.Itoa(unknownIndex) } - return usecase.Interact(func(ctx context.Context, input, output interface{}) error { + return usecase.Interact(func(ctx context.Context, input, output any) error { err := u.Interact(ctx, input, output) st := status.OK