web/gin/gin.go
package gin
import (
"context"
"log/slog"
"net/http"
"os"
"strings"
"github.com/arl/statsviz"
"github.com/gin-contrib/gzip"
"github.com/gin-gonic/gin"
sloggin "github.com/samber/slog-gin"
"github.com/wasilak/go-hello-world/utils"
ginprometheus "github.com/zsais/go-gin-prometheus"
"go.opentelemetry.io/contrib/instrumentation/github.com/gin-gonic/gin/otelgin"
"go.opentelemetry.io/otel/trace"
)
var tracer trace.Tracer
type slogWriter struct{}
func (sw slogWriter) Write(p []byte) (n int, err error) {
slog.Default().Info(string(p))
return len(p), nil
}
func Init(ctx context.Context, listenAddr, logLevel *string, otelEnabled, statsvizEnabled *bool, tr trace.Tracer, traceProvider *trace.TracerProvider) {
slog.DebugContext(ctx, "Features supported", "loggergo", true, "statsviz", true, "tracing", true)
tracer = tr
gin.DefaultWriter = slogWriter{}
// Create a Gin router
r := gin.Default()
// Prometheus Middleware
p := ginprometheus.NewPrometheus(strings.ReplaceAll(utils.GetAppName(), "-", "_"))
p.Use(r)
// OpenTelemetry Middleware
if *otelEnabled {
r.Use(otelgin.Middleware(utils.GetAppName(), otelgin.WithTracerProvider(*traceProvider)))
}
// Gzip Middleware
r.Use(gzip.Gzip(gzip.DefaultCompression))
// Custom Logging Middleware
r.Use(sloggin.New(slog.Default()))
r.Use(gin.Recovery())
// Debug Mode
if strings.EqualFold(*logLevel, "debug") {
gin.SetMode(gin.DebugMode)
slog.DebugContext(ctx, "Debug mode enabled")
}
// Define Routes
r.GET("/", mainRoute)
r.GET("/health", healthRoute)
// r.GET("/metrics", gin.WrapH(promhttp.Handler()))
// Optional Statviz
if *statsvizEnabled {
// Create statsviz server.
srv, _ := statsviz.NewServer()
// Specific route for WebSocket
r.GET("/debug/statsviz/ws", gin.WrapF(srv.Ws()))
// Static route for the index
r.GET("/debug/statsviz", func(c *gin.Context) {
c.Redirect(http.StatusMovedPermanently, "/debug/statsviz/")
})
// Define more specific routes for statsviz
r.GET("/debug/statsviz/plots", gin.WrapH(srv.Index()))
r.GET("/debug/statsviz/metrics", gin.WrapH(srv.Index()))
// Add other specific paths as needed
}
// Start Server
slog.DebugContext(ctx, "Starting server", "address", *listenAddr)
if err := r.Run(*listenAddr); err != nil {
slog.ErrorContext(ctx, "Server exited with error", "error", err)
os.Exit(1)
}
}