From 96610e0d2f9b2c6267bf4afa837c5e25f909d902 Mon Sep 17 00:00:00 2001 From: KoCoder Date: Thu, 4 Jun 2026 22:22:40 +0200 Subject: [PATCH] Migration: Depend on Service Base --- go.mod | 34 +++++------ go.sum | 25 +++----- internal/telemetry/telemetry.go | 101 -------------------------------- main.go | 56 +++++------------- 4 files changed, 39 insertions(+), 177 deletions(-) delete mode 100644 internal/telemetry/telemetry.go diff --git a/go.mod b/go.mod index db78a6b..7f66a19 100644 --- a/go.mod +++ b/go.mod @@ -8,32 +8,33 @@ tool ( ) require ( + git.kocoder.xyz/vt/service-base v1.0.0 github.com/lib/pq v1.12.3 - github.com/uptrace/opentelemetry-go-extra/otelsql v0.3.2 - go.opentelemetry.io/contrib/bridges/otelslog v0.19.0 - go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.69.0 - go.opentelemetry.io/otel v1.44.0 - go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.20.0 - go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.44.0 - go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.44.0 - go.opentelemetry.io/otel/log v0.20.0 - go.opentelemetry.io/otel/sdk v1.44.0 - go.opentelemetry.io/otel/sdk/log v0.20.0 - go.opentelemetry.io/otel/sdk/metric v1.44.0 ) require ( connectrpc.com/cors v0.1.0 // indirect github.com/rs/cors v1.11.1 // indirect + github.com/uptrace/opentelemetry-go-extra/otelsql v0.3.2 // indirect + go.opentelemetry.io/contrib/bridges/otelslog v0.19.0 // indirect + go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.69.0 // indirect + go.opentelemetry.io/otel v1.44.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.20.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.44.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.44.0 // indirect + go.opentelemetry.io/otel/log v0.20.0 // indirect + go.opentelemetry.io/otel/sdk v1.44.0 // indirect + go.opentelemetry.io/otel/sdk/log v0.20.0 // indirect + go.opentelemetry.io/otel/sdk/metric v1.44.0 // indirect ) require ( - buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go v1.36.11-20260415201107-50325440f8f2.1 // indirect + buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go v1.36.11-20260415201107-50325440f8f2.1 buf.build/go/protovalidate v1.2.0 // indirect cel.dev/expr v0.25.1 // indirect - connectrpc.com/connect v1.20.0 // indirect - connectrpc.com/grpcreflect v1.3.0 - connectrpc.com/validate v0.6.0 // indirect + connectrpc.com/connect v1.20.0 + connectrpc.com/grpcreflect v1.3.0 // indirect + connectrpc.com/validate v0.6.0 github.com/antlr4-go/antlr/v4 v4.13.1 // indirect github.com/cenkalti/backoff/v5 v5.0.3 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect @@ -43,7 +44,6 @@ require ( github.com/google/cel-go v0.28.0 // indirect github.com/google/uuid v1.6.0 // indirect github.com/grpc-ecosystem/grpc-gateway/v2 v2.29.0 // indirect - github.com/stoewer/go-strcase v1.3.1 // indirect go.opentelemetry.io/auto/sdk v1.2.1 // indirect go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.44.0 // indirect go.opentelemetry.io/otel/metric v1.44.0 // indirect @@ -56,5 +56,5 @@ require ( google.golang.org/genproto/googleapis/api v0.0.0-20260526163538-3dc84a4a5aaa // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20260526163538-3dc84a4a5aaa // indirect google.golang.org/grpc v1.81.1 // indirect - google.golang.org/protobuf v1.36.11 // indirect + google.golang.org/protobuf v1.36.11 ) diff --git a/go.sum b/go.sum index e253474..c0e8511 100644 --- a/go.sum +++ b/go.sum @@ -1,9 +1,5 @@ -buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go v1.36.9-20250912141014-52f32327d4b0.1 h1:DQLS/rRxLHuugVzjJU5AvOwD57pdFl9he/0O7e5P294= -buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go v1.36.9-20250912141014-52f32327d4b0.1/go.mod h1:aY3zbkNan5F+cGm9lITDP6oxJIwu0dn9KjJuJjWaHkg= buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go v1.36.11-20260415201107-50325440f8f2.1 h1:s6hzCXtND/ICdGPTMGk7C+/BFlr2Jg5GyH0NKf4XGXg= buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go v1.36.11-20260415201107-50325440f8f2.1/go.mod h1:tvtbpgaVXZX4g6Pn+AnzFycuRK3MOz5HJfEGeEllXYM= -buf.build/go/protovalidate v1.0.0 h1:IAG1etULddAy93fiBsFVhpj7es5zL53AfB/79CVGtyY= -buf.build/go/protovalidate v1.0.0/go.mod h1:KQmEUrcQuC99hAw+juzOEAmILScQiKBP1Oc36vvCLW8= buf.build/go/protovalidate v1.2.0 h1:DQVrUWkmGTBij+kOYv/x2LLxwcLaGKMdzShj1/6/3H0= buf.build/go/protovalidate v1.2.0/go.mod h1:7rYiQEhqvAipoazpVNBBH2S2f8bjG4huMVy1V2Yofn4= cel.dev/expr v0.25.1 h1:1KrZg61W6TWSxuNZ37Xy49ps13NUovb66QLprthtwi4= @@ -16,13 +12,16 @@ connectrpc.com/grpcreflect v1.3.0 h1:Y4V+ACf8/vOb1XOc251Qun7jMB75gCUNw6llvB9csXc connectrpc.com/grpcreflect v1.3.0/go.mod h1:nfloOtCS8VUQOQ1+GTdFzVg2CJo4ZGaat8JIovCtDYs= connectrpc.com/validate v0.6.0 h1:DcrgDKt2ZScrUs/d/mh9itD2yeEa0UbBBa+i0mwzx+4= connectrpc.com/validate v0.6.0/go.mod h1:ihrpI+8gVbLH1fvVWJL1I3j0CfWnF8P/90LsmluRiZs= +git.kocoder.xyz/vt/service-base v1.0.0 h1:WeakTvsz9389dZm3BXEbnWt2SVkLRc/9RfXjesFUqEo= +git.kocoder.xyz/vt/service-base v1.0.0/go.mod h1:FBXO015/GkyPP6CBan4Rku76Y/vrZgIL7zQyz39dTgs= github.com/antlr4-go/antlr/v4 v4.13.1 h1:SqQKkuVZ+zWkMMNkjy5FZe5mr5WURWnlpmOuzYWrPrQ= github.com/antlr4-go/antlr/v4 v4.13.1/go.mod h1:GKmUxMtwp6ZgGwZSva4eWPC5mS6vUAmOABFgjdkM7Nw= +github.com/brianvoe/gofakeit/v6 v6.28.0 h1:Xib46XXuQfmlLS2EXRuJpqcw8St6qSZz75OUo0tgAW4= +github.com/brianvoe/gofakeit/v6 v6.28.0/go.mod h1:Xj58BMSnFqcn/fAQeSK+/PLtC5kSb7FJIq4JyGa8vEs= 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/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= @@ -34,8 +33,6 @@ 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/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= -github.com/google/cel-go v0.26.1 h1:iPbVVEdkhTX++hpe3lzSk7D3G3QSYqLGoHOcEio+UXQ= -github.com/google/cel-go v0.26.1/go.mod h1:A9O8OU9rdvrK5MQyrqfIxo1a0u4g3sF8KB6PUIaryMM= github.com/google/cel-go v0.28.0 h1:KjSWstCpz/MN5t4a8gnGJNIYUsJRpdi/r97xWDphIQc= github.com/google/cel-go v0.28.0/go.mod h1:X0bD6iVNR8pkROSOoHVdgTkzmRcosof7WQqCD6wcMc8= github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= @@ -48,16 +45,10 @@ github.com/lib/pq v1.12.3 h1:tTWxr2YLKwIvK90ZXEw8GP7UFHtcbTtty8zsI+YjrfQ= github.com/lib/pq v1.12.3/go.mod h1:/p+8NSbOcwzAEI7wiMXFlgydTwcgTr3OSKMsD2BitpA= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/rodaine/protogofakeit v0.1.1 h1:ZKouljuRM3A+TArppfBqnH8tGZHOwM/pjvtXe9DaXH8= +github.com/rodaine/protogofakeit v0.1.1/go.mod h1:pXn/AstBYMaSfc1/RqH3N82pBuxtWgejz1AlYpY1mI0= github.com/rs/cors v1.11.1 h1:eU3gRzXLRK57F5rKMGMZURNdIG4EoAmX8k94r9wXWHA= github.com/rs/cors v1.11.1/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU= -github.com/stoewer/go-strcase v1.3.1 h1:iS0MdW+kVTxgMoE1LAZyMiYJFKlOzLooE4MxjirtkAs= -github.com/stoewer/go-strcase v1.3.1/go.mod h1:fAH5hQ5pehh+j3nZfvwdk2RgEgQjAoM8wodgtPmh1xo= -github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= -github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= -github.com/stretchr/testify v1.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.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= github.com/uptrace/opentelemetry-go-extra/otelsql v0.3.2 h1:ZjUj9BLYf9PEqBn8W/OapxhPjVRdC6CsXTdULHsyk5c= @@ -98,6 +89,8 @@ go.opentelemetry.io/proto/otlp v1.10.0 h1:IQRWgT5srOCYfiWnpqUYz9CVmbO8bFmKcwYxpu go.opentelemetry.io/proto/otlp v1.10.0/go.mod h1:/CV4QoCR/S9yaPj8utp3lvQPoqMtxXdzn7ozvvozVqk= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= +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/exp v0.0.0-20250911091902-df9299821621 h1:2id6c1/gto0kaHYyrixvknJ8tUK/Qs5IsmBtrc+FtgU= golang.org/x/exp v0.0.0-20250911091902-df9299821621/go.mod h1:TwQYMMnGpvZyc+JpB/UAuTNIsVJifOlSkrZkhcvpVUk= golang.org/x/net v0.55.0 h1:bcvxaJn3e1U6InsFWt1JUq1aSjnRxLzT2rtD2KfkDF8= @@ -116,7 +109,5 @@ google.golang.org/grpc v1.81.1 h1:VnnIIZ88UzOOKLukQi+ImGz8O1Wdp8nAGGnvOfEIWQQ= google.golang.org/grpc v1.81.1/go.mod h1:xGH9GfzOyMTGIOXBJmXt+BX/V0kcdQbdcuwQ/zNw42I= google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE= google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/internal/telemetry/telemetry.go b/internal/telemetry/telemetry.go deleted file mode 100644 index 32eef42..0000000 --- a/internal/telemetry/telemetry.go +++ /dev/null @@ -1,101 +0,0 @@ -package telemetry - -import ( - "context" - "errors" - "log/slog" - "strings" - - "go.opentelemetry.io/contrib/bridges/otelslog" - "go.opentelemetry.io/otel" - "go.opentelemetry.io/otel/attribute" - "go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp" - "go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp" - "go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp" - "go.opentelemetry.io/otel/log/global" - sdklog "go.opentelemetry.io/otel/sdk/log" - "go.opentelemetry.io/otel/sdk/metric" - "go.opentelemetry.io/otel/sdk/resource" - "go.opentelemetry.io/otel/sdk/trace" -) - -func newResource(serviceName string) *resource.Resource { - return resource.NewWithAttributes( - resource.Default().SchemaURL(), - attribute.String("service.name", serviceName), - ) -} - -// Init sets up OpenTelemetry tracing, metrics, and logs via OTLP Push. -// It returns a shutdown function that should be deferred in main. -func Init(ctx context.Context, endpoint string, serviceName string) (func(context.Context) error, error) { - res := newResource(serviceName) - - var shutdownFuncs []func(context.Context) error - shutdown := func(ctx context.Context) error { - var err error - for _, fn := range shutdownFuncs { - if fnErr := fn(ctx); fnErr != nil { - err = errors.Join(err, fnErr) - } - } - return err - } - - var traceOpts []otlptracehttp.Option - var metricOpts []otlpmetrichttp.Option - var logOpts []otlploghttp.Option - - if endpoint != "" { - endpoint = strings.TrimSuffix(endpoint, "/") - traceOpts = append(traceOpts, otlptracehttp.WithEndpointURL(endpoint+"/v1/traces")) - metricOpts = append(metricOpts, otlpmetrichttp.WithEndpointURL(endpoint+"/v1/metrics")) - logOpts = append(logOpts, otlploghttp.WithEndpointURL(endpoint+"/v1/logs")) - } else { - // Default to insecure localhost if no endpoint is specified - traceOpts = append(traceOpts, otlptracehttp.WithInsecure()) - metricOpts = append(metricOpts, otlpmetrichttp.WithInsecure()) - logOpts = append(logOpts, otlploghttp.WithInsecure()) - } - - // Trace setup - traceExporter, err := otlptracehttp.New(ctx, traceOpts...) - if err != nil { - return shutdown, err - } - tp := trace.NewTracerProvider( - trace.WithBatcher(traceExporter), - trace.WithResource(res), - ) - otel.SetTracerProvider(tp) - shutdownFuncs = append(shutdownFuncs, tp.Shutdown) - - // Metrics setup - metricExporter, err := otlpmetrichttp.New(ctx, metricOpts...) - if err != nil { - return shutdown, err - } - mp := metric.NewMeterProvider( - metric.WithReader(metric.NewPeriodicReader(metricExporter)), - metric.WithResource(res), - ) - otel.SetMeterProvider(mp) - shutdownFuncs = append(shutdownFuncs, mp.Shutdown) - - // Logs setup - logExporter, err := otlploghttp.New(ctx, logOpts...) - if err != nil { - return shutdown, err - } - lp := sdklog.NewLoggerProvider( - sdklog.WithProcessor(sdklog.NewBatchProcessor(logExporter)), - sdklog.WithResource(res), - ) - global.SetLoggerProvider(lp) - shutdownFuncs = append(shutdownFuncs, lp.Shutdown) - - // Route slog to OpenTelemetry - slog.SetDefault(otelslog.NewLogger(serviceName)) - - return shutdown, nil -} diff --git a/main.go b/main.go index 6705304..fc4264c 100644 --- a/main.go +++ b/main.go @@ -3,28 +3,25 @@ package main import ( "context" "log/slog" - "net/http" "os" "connectrpc.com/connect" - connectcors "connectrpc.com/cors" - "connectrpc.com/grpcreflect" "connectrpc.com/validate" + sdb "git.kocoder.xyz/vt/service-base/database" + "git.kocoder.xyz/vt/service-base/middleware" + "git.kocoder.xyz/vt/service-base/rpc" + "git.kocoder.xyz/vt/service-base/server" + "git.kocoder.xyz/vt/service-base/telemetry" "git.kocoder.xyz/vt/shortener/internal/config" "git.kocoder.xyz/vt/shortener/internal/database" "git.kocoder.xyz/vt/shortener/internal/proto/shorten/v1/shortenv1connect" "git.kocoder.xyz/vt/shortener/internal/service" - "git.kocoder.xyz/vt/shortener/internal/telemetry" _ "github.com/lib/pq" - "github.com/rs/cors" - "github.com/uptrace/opentelemetry-go-extra/otelsql" - "go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp" - "go.opentelemetry.io/otel/attribute" ) func main() { // Fallback logger for early startup errors - slog.SetDefault(slog.New(slog.NewJSONHandler(os.Stdout, nil))) + telemetry.SetupFallbackLogger() conf := config.Read() @@ -40,58 +37,33 @@ func main() { }() // Connect to DB and wrap with otelsql for database tracing - db, err := otelsql.Open("postgres", conf.DB_URL) + db, err := sdb.OpenPostgres(conf.DB_URL) if err != nil { slog.Error("failed to connect to database", slog.String("err", err.Error())) os.Exit(1) } defer db.Close() - otelsql.ReportDBStatsMetrics(db, otelsql.WithAttributes( - attribute.String("db.system", "postgresql"), - )) - dbQueries := database.New(db) srv := service.NewServer(conf, dbQueries) - mux := http.NewServeMux() + mux := rpc.NewServeMux() path, handler := shortenv1connect.NewShortenServiceHandler( service.NewShortenerService(conf, dbQueries), connect.WithInterceptors(validate.NewInterceptor()), ) - mux.Handle(path, handler) - - reflector := grpcreflect.NewStaticReflector(shortenv1connect.ShortenServiceName) - mux.Handle(grpcreflect.NewHandlerV1(reflector)) - mux.Handle(grpcreflect.NewHandlerV1Alpha(reflector)) + mux.RegisterConnect(shortenv1connect.ShortenServiceName, path, handler) mux.Handle("/", srv) - c := cors.New(cors.Options{ - AllowedOrigins: conf.ALLOWED_ORIGINS, - AllowedMethods: connectcors.AllowedMethods(), - AllowedHeaders: connectcors.AllowedHeaders(), - ExposedHeaders: connectcors.ExposedHeaders(), - MaxAge: 7200, - }) + mux.MountReflection() + + c := middleware.NewCORS(conf.ALLOWED_ORIGINS) corsMux := c.Handler(mux) - // Wrap the server with OpenTelemetry HTTP handler for tracing & metrics - instrumentedHandler := otelhttp.NewHandler(corsMux, "shortener-server2") - - p := new(http.Protocols) - p.SetHTTP1(true) - // Use h2c so we can serve HTTP/2 without TLS. - p.SetUnencryptedHTTP2(true) - s := http.Server{ - Addr: conf.LISTEN_ON, - Handler: instrumentedHandler, - Protocols: p, - } - - slog.Info("Starting server on " + conf.LISTEN_ON) - if err := s.ListenAndServe(); err != nil { + // Start server with OpenTelemetry tracing, HTTP/1.1 & HTTP/2 (h2c) support + if err := server.ListenAndServeH2C(conf.LISTEN_ON, corsMux, "shortener-server"); err != nil { slog.Error("Server failed", slog.String("err", err.Error())) } }