Files
link-shortening-service/main.go
KoCoder a9e1d1e5d9
All checks were successful
Build and Push Docker Image / build (push) Successful in 5m55s
Implement rudimentary link shortening service and wire everything together
2026-06-02 19:34:58 +02:00

87 lines
2.4 KiB
Go

package main
import (
"context"
"log/slog"
"net/http"
"os"
"connectrpc.com/connect"
"connectrpc.com/grpcreflect"
"connectrpc.com/validate"
"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/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)))
conf := config.Read()
ctx := context.Background()
shutdown, err := telemetry.Init(ctx, conf.OTLP_ENDPOINT, "shortener-server")
if err != nil {
slog.Error("Failed to initialize telemetry", slog.String("err", err.Error()))
}
defer func() {
if err := shutdown(ctx); err != nil {
slog.Error("Error shutting down telemetry", slog.String("err", err.Error()))
}
}()
// Connect to DB and wrap with otelsql for database tracing
db, err := otelsql.Open("postgres", 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()
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.Handle("/", srv)
// Wrap the server with OpenTelemetry HTTP handler for tracing & metrics
instrumentedHandler := otelhttp.NewHandler(mux, "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: ":3001",
Handler: instrumentedHandler,
Protocols: p,
}
slog.Info("Starting server on :3001")
if err := s.ListenAndServe(); err != nil {
slog.Error("Server failed", slog.String("err", err.Error()))
}
}