From 891aad41f8c0265f5991a51d9267d45b2c9fac03 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dario=20Casta=C3=B1=C3=A9?= Date: Mon, 8 Jul 2024 10:06:40 +0200 Subject: [PATCH] contrib/uptrace/bun: initial implementation (#2771) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Rodrigo Argüello --- contrib/uptrace/bun/bun.go | 82 +++++++++++ contrib/uptrace/bun/bun_test.go | 216 ++++++++++++++++++++++++++++ contrib/uptrace/bun/example_test.go | 31 ++++ contrib/uptrace/bun/option.go | 32 +++++ go.mod | 13 +- go.sum | 26 +++- 6 files changed, 396 insertions(+), 4 deletions(-) create mode 100644 contrib/uptrace/bun/bun.go create mode 100644 contrib/uptrace/bun/bun_test.go create mode 100644 contrib/uptrace/bun/example_test.go create mode 100644 contrib/uptrace/bun/option.go diff --git a/contrib/uptrace/bun/bun.go b/contrib/uptrace/bun/bun.go new file mode 100644 index 0000000000..9384806d65 --- /dev/null +++ b/contrib/uptrace/bun/bun.go @@ -0,0 +1,82 @@ +// Unless explicitly stated otherwise all files in this repository are licensed +// under the Apache License Version 2.0. +// This product includes software developed at Datadog (https://www.datadoghq.com/). +// Copyright 2024 Datadog, Inc. + +// Package bun provides helper functions for tracing the github.com/uptrace/bun package (https://github.com/uptrace/bun). +package bun + +import ( + "context" + + "github.com/uptrace/bun" + "github.com/uptrace/bun/dialect" + "gopkg.in/DataDog/dd-trace-go.v1/ddtrace" + "gopkg.in/DataDog/dd-trace-go.v1/ddtrace/ext" + "gopkg.in/DataDog/dd-trace-go.v1/ddtrace/tracer" + "gopkg.in/DataDog/dd-trace-go.v1/internal/log" + "gopkg.in/DataDog/dd-trace-go.v1/internal/telemetry" +) + +const ( + componentName = "uptrace/bun" + defaultServiceName = "bun.db" +) + +func init() { + telemetry.LoadIntegration(componentName) + tracer.MarkIntegrationImported("github.com/uptrace/bun") +} + +// Wrap augments the given DB with tracing. +func Wrap(db *bun.DB, opts ...Option) { + cfg := new(config) + defaults(cfg) + for _, opt := range opts { + opt(cfg) + } + log.Debug("contrib/uptrace/bun: Wrapping Database") + db.AddQueryHook(&queryHook{cfg: cfg}) +} + +type queryHook struct { + cfg *config +} + +var _ bun.QueryHook = (*queryHook)(nil) + +// BeforeQuery starts a span before a query is executed. +func (qh *queryHook) BeforeQuery(ctx context.Context, qe *bun.QueryEvent) context.Context { + var dbSystem string + switch qe.DB.Dialect().Name() { + case dialect.PG: + dbSystem = ext.DBSystemPostgreSQL + case dialect.MySQL: + dbSystem = ext.DBSystemMySQL + case dialect.MSSQL: + dbSystem = ext.DBSystemMicrosoftSQLServer + default: + dbSystem = ext.DBSystemOtherSQL + } + var ( + query = qe.Query + opts = []ddtrace.StartSpanOption{ + tracer.SpanType(ext.SpanTypeSQL), + tracer.ResourceName(string(query)), + tracer.ServiceName(qh.cfg.serviceName), + tracer.Tag(ext.Component, componentName), + tracer.Tag(ext.DBSystem, dbSystem), + } + ) + _, ctx = tracer.StartSpanFromContext(ctx, "bun.query", opts...) + return ctx +} + +// AfterQuery finishes a span when a query returns. +func (qh *queryHook) AfterQuery(ctx context.Context, qe *bun.QueryEvent) { + span, ok := tracer.SpanFromContext(ctx) + if !ok { + return + } + span.Finish(tracer.WithError(qe.Err)) +} diff --git a/contrib/uptrace/bun/bun_test.go b/contrib/uptrace/bun/bun_test.go new file mode 100644 index 0000000000..998aab18f8 --- /dev/null +++ b/contrib/uptrace/bun/bun_test.go @@ -0,0 +1,216 @@ +// Unless explicitly stated otherwise all files in this repository are licensed +// under the Apache License Version 2.0. +// This product includes software developed at Datadog (https://www.datadoghq.com/). +// Copyright 2024 Datadog, Inc. + +package bun + +import ( + "context" + "database/sql" + "fmt" + "os" + "testing" + + "gopkg.in/DataDog/dd-trace-go.v1/ddtrace/ext" + "gopkg.in/DataDog/dd-trace-go.v1/ddtrace/mocktracer" + "gopkg.in/DataDog/dd-trace-go.v1/ddtrace/tracer" + "gopkg.in/DataDog/dd-trace-go.v1/internal/globalconfig" + + _ "github.com/go-sql-driver/mysql" + _ "github.com/lib/pq" + _ "github.com/microsoft/go-mssqldb" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "github.com/uptrace/bun" + "github.com/uptrace/bun/dialect/sqlitedialect" + _ "modernc.org/sqlite" +) + +func TestMain(m *testing.M) { + _, ok := os.LookupEnv("INTEGRATION") + if !ok { + fmt.Println("--- SKIP: to enable integration test, set the INTEGRATION environment variable") + os.Exit(0) + } + os.Exit(m.Run()) +} + +func setupDB(t *testing.T, driverName, dataSourceName string, opts ...Option) *bun.DB { + t.Helper() + sqlite, err := sql.Open(driverName, dataSourceName) + if err != nil { + t.Fatal(err) + } + + db := bun.NewDB(sqlite, sqlitedialect.New()) + Wrap(db, opts...) + + return db +} + +func TestImplementsHook(_ *testing.T) { + var _ bun.QueryHook = (*queryHook)(nil) +} + +func TestSelect(t *testing.T) { + assert := assert.New(t) + mt := mocktracer.Start() + defer mt.Stop() + + tC := []struct { + name string + driver string + dataSource string + expected string + }{ + { + name: "SQLite", + driver: "sqlite", + dataSource: "file::memory:?cache=shared", + expected: ext.DBSystemOtherSQL, + }, + { + name: "Postgres", + driver: "postgres", + dataSource: "postgres://postgres:postgres@127.0.0.1:5432/postgres?sslmode=disable", + expected: ext.DBSystemPostgreSQL, + }, + { + name: "MySQL", + driver: "mysql", + dataSource: "test:test@tcp(127.0.0.1:3306)/test", + expected: ext.DBSystemMySQL, + }, + { + name: "MSSQL", + driver: "sqlserver", + dataSource: "sqlserver://sa:myPassw0rd@127.0.0.1:1433?database=master", + expected: ext.DBSystemMicrosoftSQLServer, + }, + } + for _, tt := range tC { + tt := tt + t.Run(tt.name, func(t *testing.T) { + db := setupDB(t, tt.driver, tt.dataSource) + parentSpan, ctx := tracer.StartSpanFromContext(context.Background(), "http.request", + tracer.ServiceName("fake-http-server"), + tracer.SpanType(ext.SpanTypeWeb), + ) + + var n, rows int64 + res, err := db.NewSelect().ColumnExpr("1").Exec(ctx, &n) + parentSpan.Finish() + spans := mt.FinishedSpans() + + require.NoError(t, err) + rows, _ = res.RowsAffected() + assert.Equal(int64(1), rows) + assert.Equal(2, len(spans)) + assert.Equal(nil, err) + assert.Equal(int64(1), n) + assert.Equal("bun.query", spans[0].OperationName()) + assert.Equal("http.request", spans[1].OperationName()) + assert.Equal("uptrace/bun", spans[0].Tag(ext.Component)) + assert.Equal(ext.DBSystemOtherSQL, spans[0].Tag(ext.DBSystem)) + mt.Reset() + }) + } +} + +func TestServiceName(t *testing.T) { + t.Run("default", func(t *testing.T) { + assert := assert.New(t) + mt := mocktracer.Start() + defer mt.Stop() + + db := setupDB(t, "sqlite", "file::memory:?cache=shared") + parentSpan, ctx := tracer.StartSpanFromContext(context.Background(), "http.request", + tracer.ServiceName("fake-http-server"), + tracer.SpanType(ext.SpanTypeWeb), + ) + + var n int + res, err := db.NewSelect().ColumnExpr("1").Exec(ctx, &n) + parentSpan.Finish() + spans := mt.FinishedSpans() + + require.NoError(t, err) + rows, _ := res.RowsAffected() + assert.Equal(int64(1), rows) + assert.Len(spans, 2) + assert.Equal(nil, err) + assert.Equal(1, n) + assert.Equal("bun.query", spans[0].OperationName()) + assert.Equal("http.request", spans[1].OperationName()) + assert.Equal("bun.db", spans[0].Tag(ext.ServiceName)) + assert.Equal("fake-http-server", spans[1].Tag(ext.ServiceName)) + assert.Equal("uptrace/bun", spans[0].Tag(ext.Component)) + assert.Equal(ext.DBSystemOtherSQL, spans[0].Tag(ext.DBSystem)) + assert.Equal(spans[0].ParentID(), spans[1].SpanID()) + }) + + t.Run("global", func(t *testing.T) { + prevName := globalconfig.ServiceName() + defer globalconfig.SetServiceName(prevName) + globalconfig.SetServiceName("global-service") + + assert := assert.New(t) + mt := mocktracer.Start() + defer mt.Stop() + + db := setupDB(t, "sqlite", "file::memory:?cache=shared") + parentSpan, ctx := tracer.StartSpanFromContext(context.Background(), "http.request", + tracer.ServiceName("fake-http-server"), + tracer.SpanType(ext.SpanTypeWeb), + ) + + var n int + res, err := db.NewSelect().ColumnExpr("1").Exec(ctx, &n) + parentSpan.Finish() + spans := mt.FinishedSpans() + + require.NoError(t, err) + rows, _ := res.RowsAffected() + assert.Equal(int64(1), rows) + assert.Equal(2, len(spans)) + assert.Equal(nil, err) + assert.Equal(1, n) + assert.Equal("bun.query", spans[0].OperationName()) + assert.Equal("http.request", spans[1].OperationName()) + assert.Equal("global-service", spans[0].Tag(ext.ServiceName)) + assert.Equal("fake-http-server", spans[1].Tag(ext.ServiceName)) + assert.Equal("uptrace/bun", spans[0].Tag(ext.Component)) + assert.Equal(ext.DBSystemOtherSQL, spans[0].Tag(ext.DBSystem)) + }) + + t.Run("custom", func(t *testing.T) { + assert := assert.New(t) + mt := mocktracer.Start() + defer mt.Stop() + + db := setupDB(t, "sqlite", "file::memory:?cache=shared", WithService("my-service-name")) + parentSpan, ctx := tracer.StartSpanFromContext(context.Background(), "http.request", + tracer.ServiceName("fake-http-server"), + tracer.SpanType(ext.SpanTypeWeb), + ) + + var n int + res, err := db.NewSelect().ColumnExpr("1").Exec(ctx, &n) + parentSpan.Finish() + spans := mt.FinishedSpans() + + require.NoError(t, err) + rows, _ := res.RowsAffected() + assert.Equal(int64(1), rows) + assert.Equal(2, len(spans)) + assert.Equal(nil, err) + assert.Equal(1, n) + assert.Equal("bun.query", spans[0].OperationName()) + assert.Equal("http.request", spans[1].OperationName()) + assert.Equal("my-service-name", spans[0].Tag(ext.ServiceName)) + assert.Equal("fake-http-server", spans[1].Tag(ext.ServiceName)) + assert.Equal("uptrace/bun", spans[0].Tag(ext.Component)) + assert.Equal(ext.DBSystemOtherSQL, spans[0].Tag(ext.DBSystem)) + }) +} diff --git a/contrib/uptrace/bun/example_test.go b/contrib/uptrace/bun/example_test.go new file mode 100644 index 0000000000..4c29f6c71b --- /dev/null +++ b/contrib/uptrace/bun/example_test.go @@ -0,0 +1,31 @@ +// Unless explicitly stated otherwise all files in this repository are licensed +// under the Apache License Version 2.0. +// This product includes software developed at Datadog (https://www.datadoghq.com/). +// Copyright 2024 Datadog, Inc. + +package bun_test + +import ( + "context" + "database/sql" + + "github.com/uptrace/bun" + "github.com/uptrace/bun/dialect/sqlitedialect" + buntrace "gopkg.in/DataDog/dd-trace-go.v1/contrib/uptrace/bun" + _ "modernc.org/sqlite" +) + +func Example() { + sqlite, err := sql.Open("sqlite", "file::memory:?cache=shared") + if err != nil { + panic(err) + } + db := bun.NewDB(sqlite, sqlitedialect.New()) + + // Wrap the connection with the APM hook. + buntrace.Wrap(db) + var user struct { + Name string + } + _ = db.NewSelect().Column("name").Table("users").Scan(context.Background(), &user) +} diff --git a/contrib/uptrace/bun/option.go b/contrib/uptrace/bun/option.go new file mode 100644 index 0000000000..586778671a --- /dev/null +++ b/contrib/uptrace/bun/option.go @@ -0,0 +1,32 @@ +// Unless explicitly stated otherwise all files in this repository are licensed +// under the Apache License Version 2.0. +// This product includes software developed at Datadog (https://www.datadoghq.com/). +// Copyright 2024 Datadog, Inc. + +package bun + +import ( + "gopkg.in/DataDog/dd-trace-go.v1/internal/globalconfig" +) + +type config struct { + serviceName string +} + +// Option represents an option that can be used to create or wrap a client. +type Option func(*config) + +func defaults(cfg *config) { + service := defaultServiceName + if svc := globalconfig.ServiceName(); svc != "" { + service = svc + } + cfg.serviceName = service +} + +// WithService sets the given service name for the client. +func WithService(name string) Option { + return func(cfg *config) { + cfg.serviceName = name + } +} diff --git a/go.mod b/go.mod index c879e8440f..eceec377d2 100644 --- a/go.mod +++ b/go.mod @@ -85,6 +85,8 @@ require ( github.com/tidwall/buntdb v1.3.0 github.com/tinylib/msgp v1.1.8 github.com/twitchtv/twirp v8.1.3+incompatible + github.com/uptrace/bun v1.1.17 + github.com/uptrace/bun/dialect/sqlitedialect v1.1.17 github.com/urfave/negroni v1.0.0 github.com/valyala/fasthttp v1.51.0 github.com/vektah/gqlparser/v2 v2.5.16 @@ -112,6 +114,7 @@ require ( honnef.co/go/gotraceui v0.2.0 k8s.io/apimachinery v0.23.17 k8s.io/client-go v0.23.17 + modernc.org/sqlite v1.28.0 ) require ( @@ -205,6 +208,7 @@ require ( github.com/jmespath/go-jmespath v0.4.0 // indirect github.com/josharian/intern v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect + github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect github.com/klauspost/compress v1.17.1 // indirect github.com/klauspost/cpuid/v2 v2.2.5 // indirect github.com/labstack/gommon v0.4.0 // indirect @@ -244,7 +248,7 @@ require ( github.com/valyala/fasttemplate v1.2.2 // indirect github.com/valyala/tcplisten v1.0.0 // indirect github.com/vmihailenco/bufpool v0.1.11 // indirect - github.com/vmihailenco/msgpack/v5 v5.3.5 // indirect + github.com/vmihailenco/msgpack/v5 v5.4.1 // indirect github.com/vmihailenco/tagparser v0.1.2 // indirect github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect github.com/xdg-go/pbkdf2 v1.0.0 // indirect @@ -272,11 +276,16 @@ require ( k8s.io/klog/v2 v2.30.0 // indirect k8s.io/kube-openapi v0.0.0-20211115234752-e816edb12b65 // indirect k8s.io/utils v0.0.0-20211116205334-6203023598ed // indirect + lukechampine.com/uint128 v1.3.0 // indirect mellium.im/sasl v0.3.1 // indirect + modernc.org/cc/v3 v3.41.0 // indirect + modernc.org/ccgo/v3 v3.16.15 // indirect modernc.org/libc v1.37.6 // indirect modernc.org/mathutil v1.6.0 // indirect modernc.org/memory v1.7.2 // indirect - modernc.org/sqlite v1.28.0 // indirect + modernc.org/opt v0.1.3 // indirect + modernc.org/strutil v1.2.0 // indirect + modernc.org/token v1.1.0 // indirect sigs.k8s.io/json v0.0.0-20211020170558-c049b76a60c6 // indirect sigs.k8s.io/structured-merge-diff/v4 v4.2.3 // indirect sigs.k8s.io/yaml v1.2.0 // indirect diff --git a/go.sum b/go.sum index dde9e28268..ecb43bd7c9 100644 --- a/go.sum +++ b/go.sum @@ -1581,6 +1581,7 @@ github.com/julienschmidt/httprouter v1.3.0 h1:U0609e9tgbseu3rBINet9P48AI/D3oJs4d github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= github.com/jung-kurt/gofpdf v1.0.0/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes= github.com/jung-kurt/gofpdf v1.0.3-0.20190309125859-24315acbbda5/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes= +github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs= github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8= github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= @@ -2048,6 +2049,10 @@ github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2 github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= github.com/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU= github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= +github.com/uptrace/bun v1.1.17 h1:qxBaEIo0hC/8O3O6GrMDKxqyT+mw5/s0Pn/n6xjyGIk= +github.com/uptrace/bun v1.1.17/go.mod h1:hATAzivtTIRsSJR4B8AXR+uABqnQxr3myKDKEf5iQ9U= +github.com/uptrace/bun/dialect/sqlitedialect v1.1.17 h1:i8NFU9r8YuavNFaYlNqi4ppn+MgoHtqLgpWQDrVTjm0= +github.com/uptrace/bun/dialect/sqlitedialect v1.1.17/go.mod h1:YF0FO4VVnY9GHNH6rM4r3STlVEBxkOc6L88Bm5X5mzA= github.com/urfave/cli v0.0.0-20171014202726-7bc6a0acffa5/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= @@ -2076,8 +2081,8 @@ github.com/vishvananda/netns v0.0.0-20210104183010-2eb08e3e575f/go.mod h1:DD4vA1 github.com/vmihailenco/bufpool v0.1.11 h1:gOq2WmBrq0i2yW5QJ16ykccQ4wH9UyEsgLm6czKAd94= github.com/vmihailenco/bufpool v0.1.11/go.mod h1:AFf/MOy3l2CFTKbxwt0mp2MwnqjNEs5H/UxrkA5jxTQ= github.com/vmihailenco/msgpack/v5 v5.3.4/go.mod h1:7xyJ9e+0+9SaZT0Wt1RGleJXzli6Q/V5KbhBonMG9jc= -github.com/vmihailenco/msgpack/v5 v5.3.5 h1:5gO0H1iULLWGhs2H5tbAHIZTV8/cYafcFOr9znI5mJU= -github.com/vmihailenco/msgpack/v5 v5.3.5/go.mod h1:7xyJ9e+0+9SaZT0Wt1RGleJXzli6Q/V5KbhBonMG9jc= +github.com/vmihailenco/msgpack/v5 v5.4.1 h1:cQriyiUvjTwOHg8QZaPihLWeRAAVoCpE00IUPn0Bjt8= +github.com/vmihailenco/msgpack/v5 v5.4.1/go.mod h1:GaZTsDaehaPpQVyxrf5mtQlH+pc21PIudVV/E3rRQok= github.com/vmihailenco/tagparser v0.1.2 h1:gnjoVuB/kljJ5wICEEOpx98oXMWPLj22G67Vbd1qPqc= github.com/vmihailenco/tagparser v0.1.2/go.mod h1:OeAg3pn3UbLjkWt+rN9oFYB6u/cQgqMEUPoW2WPyhdI= github.com/vmihailenco/tagparser/v2 v2.0.0 h1:y09buUbR+b5aycVFQs/g70pqKVZNBmxwAhO7/IwNM9g= @@ -3121,18 +3126,26 @@ k8s.io/utils v0.0.0-20211116205334-6203023598ed h1:ck1fRPWPJWsMd8ZRFsWc6mh/zHp5f k8s.io/utils v0.0.0-20211116205334-6203023598ed/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= lukechampine.com/uint128 v1.1.1/go.mod h1:c4eWIwlEGaxC/+H1VguhU4PHXNWDCDMUlWdIWl2j1gk= lukechampine.com/uint128 v1.2.0/go.mod h1:c4eWIwlEGaxC/+H1VguhU4PHXNWDCDMUlWdIWl2j1gk= +lukechampine.com/uint128 v1.3.0 h1:cDdUVfRwDUDovz610ABgFD17nXD4/uDgVHl2sC3+sbo= +lukechampine.com/uint128 v1.3.0/go.mod h1:c4eWIwlEGaxC/+H1VguhU4PHXNWDCDMUlWdIWl2j1gk= mellium.im/sasl v0.3.1 h1:wE0LW6g7U83vhvxjC1IY8DnXM+EU095yeo8XClvCdfo= mellium.im/sasl v0.3.1/go.mod h1:xm59PUYpZHhgQ9ZqoJ5QaCqzWMi8IeS49dhp6plPCzw= modernc.org/cc/v3 v3.36.0/go.mod h1:NFUHyPn4ekoC/JHeZFfZurN6ixxawE1BnVonP/oahEI= modernc.org/cc/v3 v3.36.2/go.mod h1:NFUHyPn4ekoC/JHeZFfZurN6ixxawE1BnVonP/oahEI= modernc.org/cc/v3 v3.36.3/go.mod h1:NFUHyPn4ekoC/JHeZFfZurN6ixxawE1BnVonP/oahEI= +modernc.org/cc/v3 v3.41.0 h1:QoR1Sn3YWlmA1T4vLaKZfawdVtSiGx8H+cEojbC7v1Q= +modernc.org/cc/v3 v3.41.0/go.mod h1:Ni4zjJYJ04CDOhG7dn640WGfwBzfE0ecX8TyMB0Fv0Y= modernc.org/ccgo/v3 v3.0.0-20220428102840-41399a37e894/go.mod h1:eI31LL8EwEBKPpNpA4bU1/i+sKOwOrQy8D87zWUcRZc= modernc.org/ccgo/v3 v3.0.0-20220430103911-bc99d88307be/go.mod h1:bwdAnOoaIt8Ax9YdWGjxWsdkPcZyRPHqrOvJxaKAKGw= modernc.org/ccgo/v3 v3.16.4/go.mod h1:tGtX0gE9Jn7hdZFeU88slbTh1UtCYKusWOoCJuvkWsQ= modernc.org/ccgo/v3 v3.16.6/go.mod h1:tGtX0gE9Jn7hdZFeU88slbTh1UtCYKusWOoCJuvkWsQ= modernc.org/ccgo/v3 v3.16.8/go.mod h1:zNjwkizS+fIFDrDjIAgBSCLkWbJuHF+ar3QRn+Z9aws= modernc.org/ccgo/v3 v3.16.9/go.mod h1:zNMzC9A9xeNUepy6KuZBbugn3c0Mc9TeiJO4lgvkJDo= +modernc.org/ccgo/v3 v3.16.15 h1:KbDR3ZAVU+wiLyMESPtbtE/Add4elztFyfsWoNTgxS0= +modernc.org/ccgo/v3 v3.16.15/go.mod h1:yT7B+/E2m43tmMOT51GMoM98/MtHIcQQSleGnddkUNI= +modernc.org/ccorpus v1.11.6 h1:J16RXiiqiCgua6+ZvQot4yUuUy8zxgqbqEEUuGPlISk= modernc.org/ccorpus v1.11.6/go.mod h1:2gEUTrWqdpH2pXsmTM1ZkjeSrUWDpjMu2T6m29L/ErQ= +modernc.org/httpfs v1.0.6 h1:AAgIpFZRXuYnkjftxTAZwMIiwEqAfk8aVB2/oA6nAeM= modernc.org/httpfs v1.0.6/go.mod h1:7dosgurJGp0sPaRanU53W4xZYKh14wfzX420oZADeHM= modernc.org/libc v0.0.0-20220428101251-2d5f3daf273b/go.mod h1:p7Mg4+koNjc8jkqwcoFBJx7tXkpj00G77X7A72jXPXA= modernc.org/libc v1.16.0/go.mod h1:N4LD6DBE9cf+Dzf9buBlzVJndKr/iJHG97vGLHYnb5A= @@ -3154,15 +3167,24 @@ modernc.org/memory v1.2.1/go.mod h1:PkUhL0Mugw21sHPeskwZW4D6VscE/GQJOnIpCnW6pSU= modernc.org/memory v1.7.2 h1:Klh90S215mmH8c9gO98QxQFsY+W451E8AnzjoE2ee1E= modernc.org/memory v1.7.2/go.mod h1:NO4NVCQy0N7ln+T9ngWqOQfi7ley4vpwvARR+Hjw95E= modernc.org/opt v0.1.1/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0= +modernc.org/opt v0.1.3 h1:3XOZf2yznlhC+ibLltsDGzABUGVx8J6pnFMS3E4dcq4= modernc.org/opt v0.1.3/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0= modernc.org/sqlite v1.18.1/go.mod h1:6ho+Gow7oX5V+OiOQ6Tr4xeqbx13UZ6t+Fw9IRUG4d4= modernc.org/sqlite v1.28.0 h1:Zx+LyDDmXczNnEQdvPuEfcFVA2ZPyaD7UCZDjef3BHQ= modernc.org/sqlite v1.28.0/go.mod h1:Qxpazz0zH8Z1xCFyi5GSL3FzbtZ3fvbjmywNogldEW0= modernc.org/strutil v1.1.1/go.mod h1:DE+MQQ/hjKBZS2zNInV5hhcipt5rLPWkmpbGeW5mmdw= modernc.org/strutil v1.1.3/go.mod h1:MEHNA7PdEnEwLvspRMtWTNnp2nnyvMfkimT1NKNAGbw= +modernc.org/strutil v1.2.0 h1:agBi9dp1I+eOnxXeiZawM8F4LawKv4NzGWSaLfyeNZA= +modernc.org/strutil v1.2.0/go.mod h1:/mdcBmfOibveCTBxUl5B5l6W+TTH1FXPLHZE6bTosX0= modernc.org/tcl v1.13.1/go.mod h1:XOLfOwzhkljL4itZkK6T72ckMgvj0BDsnKNdZVUOecw= +modernc.org/tcl v1.15.2 h1:C4ybAYCGJw968e+Me18oW55kD/FexcHbqH2xak1ROSY= +modernc.org/tcl v1.15.2/go.mod h1:3+k/ZaEbKrC8ePv8zJWPtBSW0V7Gg9g8rkmhI1Kfs3c= modernc.org/token v1.0.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM= +modernc.org/token v1.1.0 h1:Xl7Ap9dKaEs5kLoOQeQmPWevfnk/DM5qcLcYlA8ys6Y= +modernc.org/token v1.1.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM= modernc.org/z v1.5.1/go.mod h1:eWFB510QWW5Th9YGZT81s+LwvaAs3Q2yr4sP0rmLkv8= +modernc.org/z v1.7.3 h1:zDJf6iHjrnB+WRD88stbXokugjyc0/pB91ri1gO6LZY= +modernc.org/z v1.7.3/go.mod h1:Ipv4tsdxZRbQyLq9Q1M6gdbkxYzdlrciF2Hi/lS7nWE= nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=